C語言陣列與指標學習總結
工作之後最害怕的是對最基礎知識的考查,因此還是有必要隨時回爐學習,溫故知新。今天再次回顧總結一下C語言陣列相關知識。主要是學習《C語言陷阱與缺陷》的學習筆記。
C語言陣列值得注意的有兩點:
1,C語言中只有一維陣列,而且陣列的大小必須在編譯時期就確定下來(舊標準)。然而,C語言陣列的元素可以是任意物件,包括陣列。這樣就給多維陣列的實現或者模擬提供了可能。
2,對於陣列,我們只能夠做兩件事。一是獲取陣列的大小,二是獲得指向陣列下標為0的元素的指標。其他的任何操作雖說看起來像是陣列,但是本質上其實都是基於指標的操作。
以上兩天總結摘取自《C語言陷阱與缺陷》,讓我想起了之前自己看過的國外的一份C語言資料結構與演算法的講義。其中關於C語言陣列與指標的知識給了一個重點關注點的概括——除了作為sizeof的引數以外,其它時候C語言陣列的名稱跟指向陣列首元素的指標是等價的。
關於C語言中陣列的運算機制如何實現是關係到對陣列理解的一個重點。其實,這就是要學會(或者說是記住)C語言陣列宣告定義的形式以及含義。
1,int a[3];
定義了一個元素個數為3個的陣列a,其中每個元素都是int型別。
2, struct
{
int p[4];
double x;
}b[17];
定義了一個元素個數為17個的陣列b,其中每個元素都是一個結構體。
3,int a[12][31];
宣告定義了一個數組a,該陣列有12個元素,其中每個元素是一個擁有31個元素的陣列,每個最小子元素的型別都是int。這個地方理解時候一定不能夠按照前面兩個例子的順序,從左到右一個個數字字元進行解析。需要記住的還是最前面的那一點,C語言中只有一維陣列,而陣列名稱後面跟著的第一個數字維度就是陣列的真實維度。除此之外,其他的引數則是陣列元素的資訊描述。
陣列名稱與指向陣列的指標的等價之處在兩種表示的等價,如果定義了一個數組a,那麼陣列的下表為i的元素可以表述為:
*(a + i) 或者a[i]
實際上,後者只是前者的一種常用的簡寫方式。
而由於上面這種描述,其實a[i]和i[a]表示的含義一樣。編寫如下測試程式碼;
#include"stdio.h"
int a[5] ={1,2,3,4,5,};
int main(void)
{
printf("%d\n",a[3]);
printf("%d\n",3[a]);
return 0;
}
其中,陣列定義的時候我故意在最後的元素後面加上了一個逗號。其實,這並不是錯誤。本來我也不是很理解這種方式,在對了《UNIX程式設計藝術》一書之後才明白。其實,這算是C語言設計的一個優秀的特點,這種特徵不僅方便陣列元素的擴充時候的修改,而且方便陣列的工具生成。程式的編譯以及執行記錄如下;
E:\WorkSpace\01_程式語言\01_C語言\01_C語言陷阱與缺陷\exp02>gccexp02.c
E:\WorkSpace\01_程式語言\01_C語言\01_C語言陷阱與缺陷\exp02>a
4
4
由上面的驗證可以得出先前陳述的結論或者推論。
接下來通過簡單的程式碼,回顧二維陣列與指標的關係基礎知識。編寫程式碼如下:
E:\WorkSpace\01_程式語言\01_C語言\01_C語言陷阱與缺陷\exp02>gccexp02.c
#include"stdio.h"
int a[12][31];
int *p;
int i;
int main(void)
{
p = a[4];
printf("value of p: %p\n",p);
printf("size of a[4]:%d\n",sizeof(a[4]));
a[4][7] = 3;
i = a[4][7];
printf("value of i: %d\n",i);
i = *(a[4] + 7);
printf("value of i: %d\n",i);
i = *(*(a + 4) + 7);
printf("value of i: %d\n",i);
return 0;
}
編譯後,執行結果如下:
E:\WorkSpace\01_程式語言\01_C語言\01_C語言陷阱與缺陷\exp02>a
value of p:00405630
size of a[4]: 124
value of i: 3
value of i: 3
value of i: 3
其中,a[4]的含義自然是代表陣列a的下標為4的元素,而元素的為31個int型別物件。通過計算其佔用的空間可以看出這一點。而進一步來看,其實a[4]應該是一個31個元素的陣列的陣列名。這樣,a[4]也就等同於這個陣列的首地址。在程式中,我通過指標賦值的方式輸出了這個地址數值。接下來的元素取值就值得去品味一下了:
第一次i取值:使用了陣列名後面加中括號指明偏移來實現;
第二次i取值:進一步把第一步中的方式改成了指標取值的方式,通過首地址加偏移的方式。
第三次i取值:把迭代著的一個數組進一步展開。從最終的形式上看,這種方式比使用下標取值的簡寫方式要難理解不少。
最終i的三次輸出都是相同的,其實這也算是對三種方式等價的一個最基本的驗證。而把a賦值給p是錯誤的,因為a的含義是一個指向“二維陣列的指標”。在程式碼中加入相應的程式碼測試的時候,gcc編譯器會給出警告。不過,程式還是能夠編譯通過並執行。