首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C 語言數組越界訪問:for(i=0;i<=5;i++) 寫入 a[5] 導致 i 被覆寫

     編輯:程式設計綜合問答

代碼與現象

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] 地址是否相同。

防範措施

  1. 循環條件嚴格用 i < N,拒絕 <= N-1 或 <= N。
  2. 開啟編譯器邊界檢查:GCC -fsanitize=address -fstack-protector-all,MSVC /RTCs。
  3. 靜態分析工具:Cppcheck、Clang Static Analyzer、Coverity。
  4. 代碼規範:MISRA C Rule 18.1「循環計數器不應超出數組邊界」。

延伸思考

若編譯器將 i 放入寄存器而非棧,則 a[5] 會破壞別的變量或返回地址,導致**更難復現的崩潰**。這就是「未定義行為」的可怕之處:表現隨編譯器、優化等級、運行環境而異。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved