int a[5];
for (int i = 0; i <= 5; ++i) { // 條件應為 i < 5
a[i] = -i;
printf("a[%d] = %d\n", i, a[i]);
}
輸出中會出現 a[5] = -5,且後續 i 變為 0 導致**無限循環**(視棧布局而定)。
典型棧增長方向(高地址→低地址):
高地址
+----------------+
| a[4] a[3] | a[0] 低地址
| a[2] a[1] |
| a[0] |
+----------------+
| i | ← 緊隨數組之後
低地址
a[5] 正好覆蓋 i 的存儲單元,寫入 -5 使 i 變為 -5,下輪循環 ++i 變 -4,永遠 <=5,陷入死循環。
#include <stdio.h>
int main() {
int i = 0;
int a[5] = {0};
for (i = 0; i <= 5; i++) {
a[i] = -i;
printf("a[%d] = %d\n", i, a[i]);
if (i == 4) {
printf("&i=%p, &a[0]=%p, &a[4]=%p\n", (void*)&i, (void*)&a[0], (void*)&a[4]);
while(1); // 防止無限循環刷屏
}
}
return 0;
}
運行後對比 &i 與 &a[5] 地址是否相同。
i < N,拒絕 <= N-1 或 <= N。-fsanitize=address -fstack-protector-all,MSVC /RTCs。若編譯器將 i 放入寄存器而非棧,則 a[5] 會破壞別的變量或返回地址,導致**更難復現的崩潰**。這就是「未定義行為」的可怕之處:表現隨編譯器、優化等級、運行環境而異。