數組名在絕大多數表達式中退化為首元素地址,但 &arr、arr、&arr[0] 雖數值相同,類型與步長截然不同:
| 表達式 | 類型 | +1 步長 | 語義 |
|---|---|---|---|
&arr | int (*)[N] / int (*)[M][N] | 整個數組大小 | 指向整個數組的指針 |
arr / &arr[0] | int * / int (*)[N] | 單元素 / 一行大小 | 指向首元素 / 首行的指針 |
int a[3] = {1,2,3};
// 假設 a 起始地址 0x1000,int 4 字節
&a = 0x1000 // int (*)[3]
a = 0x1000 // int *
&a[0] = 0x1000 // int *
&a + 1 = 0x100C // +12 字節 = 3*4
a + 1 = 0x1004 // +4 字節
&a[0] + 1 = 0x1004 // +4 字節
int a[3][3]; // 3行3列,共36字節
// 假設起始 0x2000
&a = 0x2000 // int (*)[3][3]
a = 0x2000 // int (*)[3] 指向首行
&a[0] = 0x2000 // int (*)[3] 指向首行
a[0] = 0x2000 // int * 指向首元素
&a[0][0] = 0x2000 // int * 指向首元素
&a + 1 = 0x2024 // +36 字節(整個數組)
a + 1 = 0x200C // +12 字節(一行 3*4)
&a[0] + 1 = 0x200C // +12 字節(一行)
a[0] + 1 = 0x2004 // +4 字節(一個元素)
&a[0][0]+1 = 0x2004 // +4 字節
二維數組 a[3][3] 內存佈局(行優先) 地址遞增 → ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ │a[0][0]│a[0][1]│a[0][2]│a[1][0]│a[1][1]│a[1][2]│a[2][0]│a[2][1]│a[2][2]│ └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ ↑ ↑ ↑ a[0] a[1] a[2] ← int * 步長 4 a / &a[0] ← int (*)[3] 步長 12 &a ← int (*)[3][3] 步長 36
搞清 「類型決定步長」,一維二維乃至多維數組的地址偏移就不再是謎。調試時多打印 `%p` 配合 `sizeof` 驗證,比死記硬背可靠得多。