承接上一篇《語義陷阱——陣列與指標》,本文從記憶體存取機制的更深層次,剖析陣列與指標的本質差異、何時可互換、以及為何函數參數會「退化」為指標。
根據 ANSI C 標準:
a[i] 永遠等價於 *(a + i)。因此,以下情況陣列與指標可互換:
void fun(int a[]) 與 void fun(int *a) 等價。a[i]、*(a+i)、*(p+i)、p[i] (假設 p=a) 效果相同。**陣列遍歷** (for(i=0;i<10;i++) a[i]=0;):
i 位址固定 (R2),值載入 R3 — 可提至迴圈外。R4 = R1 + R3 * scale。[R4]。**指標遍歷** (p=a; for(i=0;i<10;i++) *p++=0;):
p 本身位址載入 R1 — 可提至迴圈外。p 的值 (目標位址) 到 R1。[R1]。p:R1 += R5,寫回 p 的儲存位置。**關鍵差異**:陣列名是 **編譯期常數位址** (左值不可修改);指標是 **執行期變數**,儲存著目標位址,需先讀取指標值才能間接存取。
**效率**。C 採值傳遞,若陣列按值傳遞需複製整個陣列,耗時耗空。改為傳遞首址 (指標),函數直接操作原始記憶體,避免複製開銷。這也是 C++ 引入參考傳遞 (T&) 解決同類問題的前身邏輯。
a[i] 永遠被編譯器重寫為 *(a+i)。int a[] 或 int *a 效果相同,函數內部拿到的都是指標。sizeof、&a 等),**宣告必須與定義匹配**:定義為陣列則外部宣告須為陣列;定義為指標則宣告為指標。extern char a[] 與 extern char a[100] 相容,因皆表示「某地址處有一陣列」。extern char *a 與 char a[100] **不相容**:前者表示「某地址儲存著一個指標」,後者表示「該地址即是陣列」。混用會導致間接存取錯誤。sizeof(a) 在陣列定義處給出整個陣列大小;在函數參數或表達式中 (已退化為指標) 則給出指標大小。