課堂上《C語言程序設計教程》(譚浩強版)對數組指針關系講解過於抽象,花了一晚研讀《C語言入門經典》,終於理清二維數組與多級指針的對應關系。記錄核心結論,供同路人參考。
char board[3][3] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'}
};
printf("board[0][0] = %c\n", board[0][0]); // 1
printf("*board[0] = %c\n", *board[0]); // 1
printf("**board = %c\n", **board); // 1
| 表達式 | 類型 | 語義 | 等價寫法 |
|---|---|---|---|
board | char (*)[3] | 指向首個子數組(第 0 行)的指針 | &board[0] |
*board / board[0] | char * | 指向第 0 行第 0 列元素的指針 | &board[0][0] |
**board / *board[0] / board[0][0] | char | 第 0 行第 0 列元素的值('1') | — |
board 是指向一維數組的指針(步長 3×sizeof(char))*board 解引用一次,得到指向元素的指針(步長 sizeof(char))**board 再解引用一次,得到元素值二維數組在內存中連續佈局,board[i][j] 本質上是 *(*(board + i) + j),編譯器根據類型自動計算偏移。
board == *board == **board:類型完全不同,僅數值相等時地址巧合相同。void f(char **p) 不能接收 char a[3][3],需用 void f(char (*p)[3]) 或 void f(char p[][3])。char **p = malloc(3 * sizeof(char *)) 創建的是指針數組,非連續內存,與靜態二維數組佈局不同。int a[2][3][4] 中,a 指向 int [3][4],*a 指向 int [4],**a 指向 int。每增加一維,指針鏈就多一層,解引用規則同理。
理解「數組名在表達式中退化為指向首元素的指針」是核心。二維數組首元素是一維子數組,故退化為指向一維數組的指針。畫出指針鏈圖,多寫幾個 printf("%p") 觀察地址,自然內化。