核心結論先行
| 表達式 | 類型 | 值 (位址) | +1 後位址變化 |
a | int * (指向首元素) | 陣列起始位址 | + sizeof(int) (指向 a[1]) |
&a[0] | int * | 陣列起始位址 | + sizeof(int) |
&a | int (*)[4] (指向整個陣列) | 陣列起始位址 | + sizeof(int[4]) (跨越整個陣列) |
為什麼 &a 是「指向陣列的指標」?
陣列名 a 在大多數表達式中「退化」為指向首元素的指標 (int *),但它不是指標變數 (不可修改、無儲存空間)。對一個「非指標」實體取址 (&a),編譯器視其為「以整個陣列為單一元素」的聚合體,產生指向該聚合體的指標,類型為 int (*)[N]。
類比理解:層級遞增
int i; // 0 階實體 (單一值)
int *p = &i; // 1 階指標 (指向 0 階)
int **pp = &p; // 2 階指標 (指向 1 階)
int ***ppp = &pp;// 3 階指標 ...
int a[4]; // 可視為「4 個 int 的聚合體」= 1 階聚合
int (*pa)[4] = &a; // 指向該聚合體 = 2 階
實證程式碼
#include
int main() {
int a[4] = {1,2,3,4};
printf("a = %p\n", (void*)a);
printf("a+1 = %p (diff %ld)\n", (void*)(a+1), (char*)(a+1)-(char*)a);
printf("&a[0] = %p\n", (void*)&a[0]);
printf("&a[0]+1 = %p (diff %ld)\n", (void*)(&a[0]+1), (char*)(&a[0]+1)-(char*)a);
printf("&a = %p\n", (void*)&a);
printf("&a+1 = %p (diff %ld)\n", (void*)(&a+1), (char*)(&a+1)-(char*)a);
return 0;
}
典型輸出 (64-bit 系統)
a = 0x7ffd12345670
a+1 = 0x7ffd12345674 (diff 4)
&a[0] = 0x7ffd12345670
&a[0]+1 = 0x7ffd12345674 (diff 4)
&a = 0x7ffd12345670
&a+1 = 0x7ffd12345680 (diff 16) ← 關鍵:跨越整個陣列 4*4=16 bytes
實務應用場景
- 函數參數傳遞整個陣列:
void process_matrix(int (*matrix)[4], int rows); // 保留列數資訊
int a[3][4];
process_matrix(a, 3); // a 類型自動轉為 int (*)[4]
sizeof 運算元:sizeof(a) 給出整個陣列大小 (16),而非指標大小。
- 字串字面值:
char *p = "abc"; 中 "abc" 類型為 char[4],&"abc" 為 char (*)[4]。
常見誤區