指標變數是包含記憶體位址的變數,它指向記憶體中的一塊區域,通過指標的值,可以間接訪問到相應的記憶體單元的資料,並做相應的修改。
1、指標的定義和簡單使用
定義乙個指標變數和定義一般的變數類似,只需在變數名前面加乙個「*」。對乙個指標變數賦值可以用取位址符&來獲取到乙個變數的位址,如果要獲得指標指向的記憶體區域的資料,用解參考運算子*(也稱為間接運算子,它返回其運算元指向的物件的值)。指標的值為null(null是stdio.h中定義的符號變數,實際上是0)說明其不指向任何的記憶體單元,0是唯一直接可以賦值給指標變數的整數值。實際上,*和&是互補的,當兩個運算子連續應用於乙個指標變數時,無論順序如何,運算結果相同。同時可以用printf中的格式化字串%p來輸出指標變數的值,下面是乙個簡單的程式。
#include int main()
執行結果如下:
2、用指標做函式的引數
2.1 通過指標實現的引用傳遞
程式語言的引數傳遞方式,大致分兩種:值傳遞和引用傳遞。c語言中沒有引用傳遞,但是c語言通過指標間接實現了引用傳遞。通過用指標變數作為函式的引數,可以傳遞變數的位址(只需要在變數前面加上&運算子就可以),這樣,用該位址就可以訪問到主調函式中的該變數的記憶體位址,並可以進行相應的修改。這樣,在函式執行完畢之後,修改仍然可以得到保留。
2.2 const
const限定符可以告訴編譯器特定的變數的值是不能被修改的。如果想確保函式不會修改傳遞進來的引數值,應該將引數宣告為const。這樣對於c語言中用指標實現的引用傳遞,有四種情況:指向非常量資料的非常量指標(int *aptr),指向非常量資料的常量指標(int *const aptr),指向常量資料的非常量指標(const int *aptr)和指向常量資料的常量指標(const int * const aptr)。簡單的說,就是指標變數自身和指標指向的變數都有可能是const,這樣就產生了四種情況,這四種情況提供了四種不同的訪問許可權,下面分別解釋。
指向非常量資料的非常量指標(int *aptr):指標的值本身和指標指向變數的值都可以在函式中被修改。
指向非常量資料的常量指標(int *const aptr):指標的值不能被修改,但是指標指向的變數的值可以被修改。
指向常量資料的非常量指標(const int *aptr):指標指向的值不能被修改,但是指標本身的值可以被修改。
指向常量資料的常量指標(const int * const aptr):指標本身和指標指向變數的值都不能被修改。
從別的書上看到的乙個記憶的方法,沿著*劃一條線:如果const位於*的左側(如const int *aptr),那麼可以理解為const是修飾指標指向的變數,這樣就不能通過該指標間接地修改該變數的值;如果const位於*的右側(int *const aptr),那麼說明這個const是修飾的指標本身,這樣的話就不可以修改該指標使它指向其它變數;如果兩邊都有const(const int * const aptr),那說明指標本身和指標指向變數的值都不可以修改。至於左側右側容易記混的問題,其實很容易解決,因為這樣想就好了,*左側是指標指向的變數型別啊,const放在這兒,很明顯是在修飾指標指向的物件啊,記住左側,右側就反著好了
3、sizeof和指標運算
3.1 sizeof
sizeof是c語言中特殊的一元運算子,可以應用在變數名稱、資料型別和常量之前,它在程式編譯期間以位元組為單位來確定陣列或其他資料型別的大小。當應用於陣列時,sizeof返回陣列中的位元組總數。如float a[20],sizeof(a)的值應該是4*20,80。當然,如果想獲得陣列的大小可以採用sizeof(a)/sizeof(float)。
3.2 指標運算
實際上,指標變數可以進行的算術操作是有限的:遞增,遞減,將指標和整數相加,從指標中減去乙個整數或者乙個指標減去另乙個指標。需要注意的是,對於指標的算術運算,其單位長度並不是一般意義上的1,而是sizeof(type)。這樣,如果float a[14]; float *aptr=a;(或者int *aptr=&a[0]); aptr++;這樣aptr應該指向的是陣列a的第二個元素,也就是a[1],這裡的單位長度就是sizeof(float)。同樣地,如果aptr=aptr+5;,這樣aptr又指向了陣列a的第6個元素。如果aptr-a,這樣可以得到兩個指標之間的元素間隔個數。應該是6。
進行指標運算要注意:
(1)如果將乙個指標的值賦給另外乙個指標,那麼這兩個指標的型別必須相同,否則應該用型別轉換運算子進行型別轉換。但是,有乙個例外就是指向void型別的指標,它是通用指標,可以代表任何指標型別。因此,所有指標型別都可以賦值給void指標,而void指標也可以賦值給任何型別的指標,而不需要任何型別轉換運算子。但是,void指標不能解參考,編譯器知道指向int型別的指標引用的是32位計算機上的4個位元組記憶體,但指向void的指標僅包含未知資料型別的記憶體位置,也就是說,編譯器不知道指標所引用的位元組數。編譯器必須知道資料型別,才能確定所引用的位元組數。
(2)除非兩個指標變數都指向的是乙個陣列中的元素,否則對它們相減的結果沒有任何意義,因為我們不能假設兩個變數在記憶體中是連續的。
4、指標和陣列
4.1 陣列和指標的共性
實際上,陣列名稱的本質是乙個常量指標。因此,int a[6]; int *aptr;定義乙個陣列和指標之後,通過a[3],*(a+3)和*(aptr+3)都可以訪問到陣列的第四個元素的值。但是區別在於,aptr=aptr+3;這樣aptr就指向了a陣列的第四個元素,但是,不能a=a+3;,因為a是乙個陣列名,它是乙個常量指標它的值不能被修改,更加具體地說,它應該是乙個指向非常量資料的常量指標。
4.2 指標陣列
陣列元素也可以是指標型別,指標陣列常見的用途就是構成由字串組成的陣列,簡單地說就是字串陣列,陣列中的每乙個元素都是字串。下面是乙個例子,const限定符說明不能修改每個元素指標所指向的字串。
#includeint main()
; int i;
for(i=0;i<4;i++)
printf("sizeof pointer to \"%s\" :%d\n",suit[i],sizeof(suit[i]));
printf("\nsizeof suit:%d\n",sizeof(suit));
return 0;
}
執行結果如下:
從這個例子中,可以看出const char *suit[4]=;定義了乙個指標陣列,但是,其中的每個元素只是乙個指標,而不是陣列名(如果是陣列名的話,sizeof的結果不應該都是4)。這樣定義字串陣列可以節省空間。
5、函式指標
和陣列名實際上就是陣列第乙個元素在記憶體中的位址類似,函式迷你實際上就是執行函式任務的**在記憶體中的起始位址。函式指標包含函式在記憶體中的位址,可以傳遞給函式、從函式返回、儲存在陣列中或者是賦值給其它的函式指標,下面是兩個函式指標的例子。
(1) 用函式指標實現公升序/降序排序
#include #define size 10
int ascending(int a,int b)
int descending(int a,int b)
; int choice;
printf("enter a number between 0 and 2, 3 to end: ");
scanf("%d",&choice);
while(choice >=0 && choice<3)
printf("program execution completed.\n");
return 0;
}void function1(int a)
void function2(int a)
void function3(int a)
執行結果:
參考
C語言指標
1 定義指標變數void change int n 格式 變數型別 變數名 定義了乙個指標變數p 指標變數只能儲存位址 指標變數p前面的int 指標變數p只能指向int型別的資料 int main void change int n 2 指標與陣列 陣列名其實質是乙個指標,但是它和普通的指標變數還是...
c語言指標
編寫程式,在主函式裡用指標陣列輸入六個字串,再用另乙個函式對這六個字串排序,並在主函式中輸出排好序的字串。include void sort char s,int n char temp for int i 0 ifor int j 0 jif strcmp s j s j 1 0 temp s j...
C語言 指標
指標的基礎知識點 指標其實就是位址,是用來儲存變數的。通常在定義乙個整形變數是這樣定義的 int a 2 定義乙個整形指標是這樣的 int p a 就是乙個宣告,宣告p是乙個指標,用來儲存a的位址,就是取位址符,把變數a的位址取出來賦給指標變數p 如果輸出printf d p 輸出的結果是2,因為輸...