標籤:指標 數組 數組的數組
(5)c數組本質
c中的數組是一種彙總類型,把同種類型的元素按順序儲存,即是數組。c中數群組類型的特點在於:它是嵌套定義的。
看下一個二維數組int array[2][3]={{1,2,3},{4,5,6}};的記憶體儲存形式:
c中的數組是嵌套定義的:二維數組的元素是一維數組,三維數組的元素是二維數組……
像array[2][3]這樣的二維數組,是由兩個一維數組組成的:array[0]、array[1],這兩個一維數組的規模都是array的第二個下標3。同時,array[0]、array[1]就是兩個一維數組名。由於元素都是順序儲存的,故可以通過以下的方式挨個訪問array中元素:
int main(void){int array[2][3] = {{ 1, 2, 3 },{ 4, 5, 6 }};//讓p指向數組首元素int *p = &array[0][0];while (p < &array[1][3]){printf("%4d", *p);p++;}printf("\n\n");return 0;}
運行
這種訪問方式能夠成功,關鍵就在於c中的多維陣列本質是數組的數組,並且元素順序儲存。
在代碼中出現了&array[1][3],是不是越界了呢?理論上array[1][2]是array的最後一個元素,array[1][3]正好是其下一個,這裡我們取其地址,而不是訪問元素,這是可以的。
下面來探討一下這三個數組名:array、array[0]和array[1]是何種類型的指標。
首先,在(3)數組和指標中,我們提到過,對於數組int array[N];(N是一常量)。數組名array是一指向數組首元素的常量指標(也就是說,不可再指向別的儲存單元),而&array是一指向整個數組的指標。這裡以此類推:
- array[0]是指向array[0][0]的指標,類型是int *。&array[0]是指向數組的指標,類型是int(*)[3]。
- array[1]和array[0]類型相同,&array[1]和&array[0]的類型相同。當然,只是類型相同,值不同。
- array應是指向array[0]的指標,而array[0]是一個一維數組int [3],故array是一個指向一維數組的指標,類型是int(*)[3]。&array應是指向整個二維數組的指標,類型是int(*)[2][3]。
做實驗驗證:
int main(void){int array[2][3] = {{1, 2, 3},{4, 5, 6}};int *pa = array[0];int (*pb)[3] = &array[0];int (*pc)[3] = array;int (*pd)[2][3] = &array;return 0;}
編譯下,無任何警告,我們的猜想正確。以上兩個實驗可以充分說明c數組的本質:
數組的數組。
小測一下;三維數組 int array[2][3][4]; array的類型?&array的類型?array[0]的類型?array[0][0]的類型?(答案在最後,先想想,再看答案。)
另一種測試,使用指標運算來驗證
int main(void){int array[2][3] = {{1, 2, 3},{4, 5, 6}};int *pa = array[0];int (*pb)[3] = &array[0];int (*pc)[3] = array;int (*pd)[2][3] = &array;printf("array...%p\n", array);printf(" pa+1...%p\n", pa + 1);printf(" pb+1...%p\n", pb + 1);printf(" pc+1...%p\n", pc + 1);printf(" pd+1...%p\n", pd + 1);return 0;}
運行
計算後四者和array的差值,結論即可得到。
總結c數組的本質是:數組的數組。至於數組名 array 和 &array 的指標類型問題,只需記憶兩點,其它可推理。這兩點是:
- array指向數組首元素,弄清楚了元素類型是什麼,指標類型自然就推出來了。
- &array被規定為指向整個數組,它的類型更簡單。
測試答案array的類型是int(*)[3][4];&array的類型是int(*)[2][3][4];array[0]的類型是int(*)[4];array[0][0]的類型是int*。
專欄目錄:C指標