陣列索引即指標算術
方括號下標 a[i] 感覺像是陣列內建的功能,但在 C 裡它純粹是指標算術的語法糖。按定義,a[i] 的意義就完全等同於 *(a + i):拿到指標、往前走 i 個元素、然後解參考。索引不是另一套機制——它只是把你已經懂的兩件事打扮得好讀一些。
以 a 是 int *、計算 a[2] 為例走一遍:先 a + 2 前進兩個元素,即 2 * sizeof(int) = 8 個位元組,到達第三個 int 的位址;接著 * 解參考那個位址,讀或寫那裡的值。因為 a[i] 字面上就定義為 *(a + i),而加法可交換,所以看起來很怪的 i[a] 也合法、且意義相同——這是「下標只是算術」的一個古怪證明。這也解釋了為什麼能對退化後的陣列做索引:一旦 int a[10] 變成指標,a[i] 就只是對那個指標做指標算術。
由此有兩個誠實的後果。第一,沒有自動的邊界檢查——a[i] 不管 i 是否在範圍內,都會算出一個位址並解參考它,所以對 10 個元素的陣列做 a[100] 是越界存取、是未定義行為,也是無數緩衝區溢位的根源。第二,索引與指標真的可以互換:p[i]、*(p + i)、以及用 p++ 走訪,是表達同一趟走訪的三種寫法,你選哪一種是清晰度的問題,不是能力的問題。
int a[3] = {5, 6, 7}; ——那麼 a[1]、*(a + 1)、甚至 1[a] 全都求值為 6。編譯器把 a[1] 變成 *(a + 1):從起點往前一個元素(4 位元組),再解參考。
a[i] 的定義就是 *(a + i)——下標是算術的語法糖。
因為 a[i] 只是 *(a + i),下標從不檢查 i 是否有效。超出結尾(或為負)的索引會悄悄算出一個壞位址並在那裡讀寫——這是未定義行為,不是保證會當掉。在 C 裡,讓索引保持在範圍內完全是程式設計者的責任。