指標與陣列的關係是 C 語言最核心也最易混淆的主題。本文系統闡述**陣列降級規則**、**指標算術**、**sizeof 非降級例外**、**記憶體佈局差異**,並修正原始碼中「多個指標指向同一目標」的表述不精確問題。
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = arr; // 降級:arr → &arr[0],型別 int*
// 等價操作:
arr[i] ≡ *(arr + i) ≡ *(p + i) ≡ p[i]
&arr[i] ≡ arr + i ≡ p + i
| 運算子 | 運算式 | 結果型別 | 說明 |
|---|---|---|---|
| sizeof | sizeof(arr) | size_t (40) | 整個陣列大小,非指標大小 |
| & (取址) | &arr | int (*)[10] | 陣列指標,指向整個陣列 |
| 運算式 | 值 | 型別 | 說明 |
|---|---|---|---|
| sizeof(arr) | 40 | size_t | 10×4,陣列完整大小 (不降級) |
| sizeof(p) | 8 | size_t | 指標大小 (64位=8) |
| sizeof(arr[0]) | 4 | size_t | 單元素大小 (降級後取元素) |
| sizeof(&arr) | 8 | size_t | 陣列指標大小 (不降級) |
| sizeof(&arr[0]) | 8 | size_t | 元素指標大小 |
| sizeof(*&arr) | 40 | size_t | &arr 為陣列指標,*解參考得陣列,sizeof 不降級 |
陣列 int arr[10]: +----+----+----+----+----+----+----+----+----+----+ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 連續 40 位元組 +----+----+----+----+----+----+----+----+----+----+ ^ ^ arr (降級為 &arr[0]) arr+9 指標 int *p = arr: +----+ | | ← 8 位元組 (64位),儲存位址值 (如 0x7fff...) +----+ ^ p (獨立變數,有自己的位址 &p)
int matrix[3][4]; int (*p)[4] = matrix; // 正確:matrix 降級為 int(*)[4] (指向 4 個 int 的陣列) int *p2 = matrix[0]; // 第一行降級為 int* int *p3 = &matrix[0][0]; // 同前 // 函數參數 void f(int arr[3][4]) ≡ void f(int (*arr)[4]) // 必須保留列數 void f(int *arr) // 錯誤:丟失列數,無法正確索引 arr[i][j]
int a[5] = {1,2,3,4,5};
printf("%p\n", a); // 首元素位址
printf("%p\n", &a); // 陣列位址 (數值相同,型別不同)
printf("%p\n", a+1); // 首元素位址 + sizeof(int)
printf("%p\n", &a+1); // 陣列位址 + sizeof(int[5]) = +20 位元組
printf("%zu\n", sizeof(a)); // 20
printf("%zu\n", sizeof(&a)); // 8 (指標大小)
**陣列降級規則**是 C 指標系統的基石:**多數情況降級為首元素指標,僅 `sizeof` 和 `&` 保留陣列完整型別資訊**。指標與陣列在記憶體佈局上本質不同:前者是獨立位址變數,後者是連續資料區塊。掌握 `sizeof` 非降級例外、函數參數退化、二維陣列指標型別,是從「會用指標」進化為「懂記憶體模型」的關鍵門檻。