c语言指针的相关运算,C语言指针的运算
本文討論使用指針進(jìn)行的運(yùn)算,最重要的運(yùn)算是獲取指針?biāo)玫膶ο蠡蚝瘮?shù)。也可以比較指針,使用指針來遍歷一個內(nèi)存區(qū)域。
使用指針讀取與修改對象
間接運(yùn)算符 * 生成內(nèi)存中的位置,該位置的地址存儲在一個指針中。如果 ptr 是一個指針,那么 *ptr 就是 ptr 所指向的對象(或函數(shù))。
使用間接運(yùn)算符有時候被稱為解引用(dereferencing)一個指針。指針指向的內(nèi)存位置被認(rèn)為存儲有一個對象,指針的類型決定了該對象的類型。例如,當(dāng)用 int 指針獲取一個特定內(nèi)存位置,讀出或?qū)懭氲囊彩?int 類型的對象。
與乘法運(yùn)算符 * 不同,間接運(yùn)算符 * 是一元運(yùn)算符,也就是說,間接運(yùn)算符只有一個操作數(shù)。在例 1 中,ptr 指向變量 x。因此,表達(dá)式 *ptr 等效于變量 x 本身。
【例1】解引用一個指針double x, y, *ptr; // 兩個double變量和一個double指針 ptr = &x; // 使得ptr指向x *ptr = 7.8; // 對變量x賦值7.8 *ptr *= 2.5; // 將x乘以2.5 y = *ptr + 0.5; // 將加法x+0.5的結(jié)果賦值給y
不要混淆指針聲明中的星號(*)和間接運(yùn)算符。聲明中的語法可以被視為展示了如何使用指針。如下例所示:double *ptr;
如上述聲明,ptr 具有 double* 類型(讀為:“指向double的指針”)。因此,表達(dá)式 *ptr 類型是 double。
當(dāng)然,間接運(yùn)算符 * 必須匹配一個具有有效地址的指針。這個用法要求在編寫程序時需要特別小心!例 1 中,如果沒有 ptr=&x 為 ptr 分配有效地址,那么所有包含 *ptr 的語句都是沒有意義的(解引用一個沒有定義的指針),有可能會造成程序崩潰。
一個指針變量,其本身也是內(nèi)存中的一個對象,也就是說,其他指針可以指向該指針。若想創(chuàng)建指針的指針,必須使用兩個星號,如下例所示:char c = 'A', *cPtr = &c, **cPtrPtr = &cPtr;
表達(dá)式 *cPtrPtr 當(dāng)前生成 char 指針 cPtr,而 **cPtrPtr 的值是 char 變量 c。圖 1 展示了這樣的關(guān)系。
圖1
指針的指針不僅限于兩個層次的間接運(yùn)算。也可以根據(jù)自己的需要定義多個層次的間接運(yùn)算。然而,不能通過多次使用地址運(yùn)算符 & 來取得指針的值:char c = 'A', **cPtrPtr = &(&c); // 錯誤!
上例中的第二個初始化語句是非法的:表達(dá)式(&c)不可以作為 & 的操作數(shù),因為它不是一個左值。換句話說,在本例中,不存在可以讓 cPtrPtr 指向的 char 指針。
如果將一個指針采用引用方式傳入函數(shù),以讓函數(shù)可以修改該指針的值,那么該函數(shù)的參數(shù)就是指針的指針。下面簡單的例子是一個函數(shù),動態(tài)地創(chuàng)建一個新的記錄,將其地址存儲在一個指針變量中:#include // 記錄的類型: typedef struct { long key; /* ... */ } Record; _Bool newRecord( Record **ppRecord ) { *ppRecord = malloc( sizeof(Record) ); if ( *ppRecord != NULL ) { /* ...初始化新記錄的成員... */ return 1; } else return 0; }
下列語句是調(diào)用函數(shù) newRecord()的一種可能方式:Record *pRecord = NULL; if ( newRecord( &pRecord) ) { /* ...pRecord現(xiàn)在指向了一個新的Record對象... */ }
表達(dá)式 *pRecord 生成新的記錄,并且(*pRecord).key 是該記錄中的 key 成員。表達(dá)式(*pRecord).key 中的括號是有必要的,因為點(diǎn)運(yùn)算符(.)比間接運(yùn)算符(*)具有更高的優(yōu)先級。
不用上面運(yùn)算符與括號結(jié)合的方式,也可以使用箭頭運(yùn)算符 -> 來獲取結(jié)構(gòu)或聯(lián)合的成員。如果 p 是一個指向結(jié)構(gòu)或聯(lián)合的指針,并且該結(jié)構(gòu)或聯(lián)合具有成員 m,那么表達(dá)式 p->m 等效于(*P).m。因此,下面的語句將一個值賦值給 pRecord 所指的 key 成員:pRecord->key = 123456L;
修改和比較指針
除了使用賦值操作讓一個指針引用一個給定的對象或函數(shù),也可以使用算術(shù)運(yùn)算來修改一個對象指針。當(dāng)進(jìn)行指針?biāo)阈g(shù)運(yùn)算(pointer arithmetic)時,編譯器會自動在運(yùn)算中采用指針?biāo)割愋偷目臻g大小。
對于指向?qū)ο蟮闹羔?#xff0c;可以進(jìn)行下列的運(yùn)算:
(1) 對一個指針執(zhí)行整數(shù)加法和減法操作。
(2) 兩個指針相減。
(3) 比較兩個指針。
當(dāng)將兩個指針相減時,這兩個指針必須具有相同的基本類型,但是類型限定符則不需要一樣。而且,可以使用相等運(yùn)算符(==和!=)來將任何指針與空指針常量比較,也可以將對象指針與 void 指針比較。
這里所描述的三種指針運(yùn)算,通常只針對指向數(shù)組元素的指針時才有用。為了展示這些運(yùn)算的作用,假設(shè)有兩個指針 p1 和 p2,它們都指向數(shù)組 a 內(nèi)的元素:
(1) 如果 p1 指向數(shù)組元素 a[i],并且 n 是一個整數(shù),那么表達(dá)式 p2=p1+n 的使得 p2 指向數(shù)組元素 a[i+n](假設(shè) i+n 仍在數(shù)組 a 的索引范圍內(nèi))。
(2) 減法 p2-p1 的結(jié)果是獲得兩個指針之間數(shù)組元素的數(shù)量,結(jié)果的類型是 ptrdiff_t。該類型定義在頭文件 stddef.h 中,通常定義成 int。在賦值運(yùn)算 p2=p1+n 之后,表達(dá)式 p2-p1 的值是 n。
(3) 如果 p2 所引用的元素比 p1 所引用的元素具有更大的索引值,則 p1
。因為一個數(shù)組的名稱會隱式地轉(zhuǎn)換為指向數(shù)組第一個元素的指針,所以可以把數(shù)組的下標(biāo)表示法替換為指針?biāo)阈g(shù):
(1) 表達(dá)式 a+i 是指向 a[i] 的指針,而 *(a+i)的值是元素 a[i]。
(2) 表達(dá)式 p1-a 的結(jié)果是 p1 指向元素的索引值 i。
在例 2 中,函數(shù) selection_sortf()對 float 元素數(shù)組進(jìn)行排序,使用選擇性排序算法。這個函數(shù)使用指針而非索引完成對 float 元素數(shù)組的排序,函數(shù)swapf()維持不變。
【例2】指針版本的函數(shù) selection_sortf()// 函數(shù)swapf()交換兩個float變量的值 // 參數(shù):兩個指向float的指針 inline void swapf( float *p1, float *p2 ) { float tmp = *p1; *p1 = *p2; *p2 = tmp; // 交換*p1和*p2 } // 函數(shù)selection_sortf()使用選擇性排序算法,對float元素數(shù)組排序 // 參數(shù):一個float元素數(shù)組,以及它的長度 void selection_sortf( float a[], int n ) // 對有n個float元素的數(shù)組a進(jìn)行排序 { if ( n <= 1 ) return; // 不進(jìn)行排序 register float *last = a + n-1, // 指向最后一個元素的指針 *p, // 指向一個選定元素的指針 *minPtr; // 指向當(dāng)前最小值元素的指針 for ( ; a < last; ++a ) // 將指針遍歷整個數(shù)組 { minPtr = a; // 在a所指的元素與最后一個元素之間 for ( p = a+1; p <= last; ++p ) // 找到最小值元素 if ( *p < *minPtr ) minPtr = p; swapf( a, minPtr ); // 將最小值元素與a所指的元素交換 } }
通常來講,指針版本的函數(shù)比使用索引版本的函數(shù)具有更高效率,因為使用索引 i 獲取數(shù)組 a 的元素,表達(dá)式為 a[i] 或 *(a+i),它涉及將 a 的地址加上 i*sizeof(元素類型)的值,以獲得對應(yīng)的數(shù)組元素地址。指針版本相比之下需要的運(yùn)算就少得多了,因為指針本身可遞增,不需要索引,并且指針直接指向所需的元素。原文始發(fā)于:C語言指針的運(yùn)算
總結(jié)
以上是生活随笔為你收集整理的c语言指针的相关运算,C语言指针的运算的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言随机产生100个字母,C语言实现产
- 下一篇: c语言程序二级考试题,2016年计算机二