| 表達式 | 類型 | 值 | 含義 |
a | int* | 首元素位址 | 退化為 &a[0] |
&a | int(*)[5] | 整個陣列位址 | 行指標,指向含 5 個 int 的陣列 |
指標運算差異
int a[5] = {1,2,3,4,5};
int *p1 = a; // p1 = &a[0] = 0x1000
int *p2 = (int*)(&a + 1); // &a + 1 跨過整個陣列 = 0x1000 + 5*4 = 0x1014
關鍵:&a + 1 的步長是 **整個陣列大小** (sizeof(int[5]) = 20 位元組),而 a + 1 步長是 **單個元素** (4 位元組)。
經典面試題解析
int a[5] = {1,2,3,4,5};
int *p = (int*)(&a + 1);
printf("%d\n", *(p-1)); // 輸出?
逐步推導
&a 類型 int(*)[5],值 0x1000
&a + 1 類型同,值 0x1000 + 20 = 0x1014 (指向陣列結束後)
(int*)(&a + 1) 強轉為 int*,值 0x1014
p - 1 類型 int*,值 0x1014 - 4 = 0x1010
*(p-1) 解引用 0x1010,即 a[4] = 5
記憶體佈局視覺化
位址: 0x1000 0x1004 0x1008 0x100C 0x1010 0x1014
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+
a[ ]: | 1 | | 2 | | 3 | | 4 | | 5 | | |
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+
索引: 0 1 2 3 4
a: 0x1000 (int*)
&a: 0x1000 (int(*)[5])
&a+1: 0x1014 (int(*)[5]) ----> 跨過 5 個 int
p: 0x1014 (int*)
p-1: 0x1010 (int*) -----> 指向 a[4]
*(p-1): 5
行指標完整語法
int a[3][4]; // 3行4列
int (*p)[4] = a; // p 指向「含4個int的陣列」,即第0行
p++; // p 指向第1行,步長 16 位元組
int *elem = *(p+1)+2; // 第1行第2列的位址 (&a[1][2])
int val = *(*(p+1)+2); // 第1行第2列的值 (a[1][2])
常見錯誤與最佳實踐
| 錯誤代碼 | 問題 | 正確寫法 |
int *p = &a; | 類型不匹配:int(*)[5] vs int* | int (*p)[5] = &a; 或 int *p = a; |
sizeof(p) 當作陣列大小 | p 是指標,sizeof 為 4/8 | sizeof(a) 才是陣列總大小 |
函式參數 void f(int a[]) 用 sizeof | 退化為指標,sizeof 失效 | 傳遞長度參數或用結構體包裹 |
總結
a 是首元素位址 (int*),&a 是整個陣列位址 (int(*)[N])。指標運算步長由**指標類型**決定:int* 步長 4,int(*)[5] 步長 20。強轉類型改變步長語義,是陣列邊界計算、多維陣列操作的核心技巧。
- 上一篇文章: C語言順序表(線性表)完整實作:初始化、插入、刪除、查找
- 下一篇文章: C語言字串操作完全指南:標準庫函式、寬字元、安全替代方案
Copyright ©
程式碼之家 All Rights Reserved