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

C 語言除錯實戰:記憶體錯誤排查與除零陷阱

     編輯:C 語言問答

經典案例:一段看似正確卻會崩潰的代碼

#include <stdio.h>

int main() {
    int x, y, a[500], b, c = 0, d, e;
    for (x = 100, y = 188 - x, b = 0; x <= 188; x++, b++) {
        a[b] = (170 - y) * (550 / (x - 100));  // 💣 危險!
        if (c < a[b]) {
            c = a[b]; d = x; e = y;
        }
    }
    printf("攻擊為 %d\n防御為 %d\n傷害為 %d", x, y, c);
    return 0;
}

錯誤複現與分析

程式編譯通過,執行卻拋出「記憶體錯誤」或直接崩潰。罪魁禍首在於第 6 行:

a[b] = (170 - y) * (550 / (x - 100));

當 x = 100 時,分母 (x - 100) = 0,觸發 整數除零 (Division by Zero),導致未定義行為 (UB),典型表現為程式崩潰或拋出 SIGFPE 信號。

修正方案

  1. 調整迴圈起始值:將 x = 100 改為 x = 101,避開除零點。
  2. 加入防禦性檢查:
    if (x != 100) {
        a[b] = (170 - y) * (550 / (x - 100));
    } else {
        a[b] = 0; // 或其他預設值
    }
    
  3. 使用浮點運算避免整數截斷:若需精確比例,改用 double 並最後四捨五入。

進階除錯技巧

工具/技巧用法適用場景
AddressSanitizer (ASan)gcc -fsanitize=address -g test.c緩衝區溢位、Use-after-free、雙重釋放、堆疊溢位
Valgrind Memcheckvalgrind --leak-check=full ./test記憶體洩漏、非法讀寫、未初始化變數
GDB 斷點除錯gdb ./test → break 6 → run → print x逐步追蹤變數值、呼叫堆疊、條件斷點
Visual Studio 除錯器F9 設斷點 → F5 啟動 → 監看視窗輸入 x-100Windows 原生開發、混合模式除錯、記憶體視窗
編譯器警告gcc -Wall -Wextra -Wpedantic -Werror編譯期捕捉除零風險、隱式轉換、未使用變數

舉一反三:常見 UB 陷阱清單

  • 除零:整數/浮點數除以 0。
  • 有號整數溢位:INT_MAX + 1、INT_MIN - 1。
  • 空指標解引用:int *p = NULL; *p = 1;。
  • 陣列越界:int a[10]; a[10] = 0;。
  • 未初始化變數:int x; printf("%d", x);。
  • 釋放後使用:free(p); *p = 1;。
  • 雙重釋放:free(p); free(p);。
  • 移位超寬:1 << 32 (在 32 位元 int 上)。

核心心法
1. 開啟最高警告等級 並視警告為錯誤 (-Werror)。
2. 善用 Sanitizer:-fsanitize=address,undefined 能在執行期精準定位 UB。
3. 防禦性程式設計:除法前檢查分母、指標解引用前檢查非空、陣列存取前檢查索引範圍。
4. 單元測試覆蓋邊界值:0、-1、MAX、MIN、NULL、空字串。

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