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

《12 個有趣的 C 語言問答》評析(二):內存管理陷阱與標準合規

     編輯:關於C語言

延續上篇,本文聚焦內存分配、釋放、錯誤處理等工程核心環節。原文示例違反 C 標準、引入未定義行為、忽略資源洩露,是典型的「能跑但不能用」的代碼。

第 3 題:main 返回類型與內存洩露

原文問題代碼

void main(void) {  // 錯誤:非標準簽名
    char *ptr = malloc(10);
    if (NULL == ptr) { printf("Malloc failed"); return; }
    // 處理...
    free(ptr);
    return;  // 無返回值
}

標準合規版

// C99/C11 標準簽名
int main(void) {
    char *ptr = malloc(10);
    if (!ptr) {
        fprintf(stderr, "Malloc failed\n");
        return EXIT_FAILURE;  // 
    }
    
    // 業務邏輯...
    
    free(ptr);
    return EXIT_SUCCESS;
}

關鍵糾正點

第 4 題:strncpy 陷阱與字符串安全

原文問題代碼

memset(ptr, 0, 10);
strncpy(ptr, argv[1], 9);  // 不保證 \0 結尾!
while (*ptr != 'z') {
    if (*ptr == '\0') break;  // 邏輯脆弱
    ptr++;
}

strncpy 致命缺陷

  • 源串長度 ≥ n 時,不添加 \0,目標串非法
  • 源串長度 < n 時,填充 \0 到 n,性能浪費
  • 返回值為目標地址,無法判斷是否截斷

安全替代方案

// 方案 1:手動保證 \0(最通用)
strncpy(ptr, argv[1], 9);
ptr[9] = '\0';  // 強制結尾

// 方案 2:snprintf(C99,推薦)
snprintf(ptr, 10, "%s", argv[1]);  // 保證 \0,返回寫入長度

// 方案 3:strlcpy(BSD,Linux 需自行實現)
// strlcpy(ptr, argv[1], 10);

// 方案 4:calloc + strncpy(原文修正版)
char *ptr = calloc(10, 1);  // 自動歸零
strncpy(ptr, argv[1], 9);   // 此時安全:即使無 \0,緩衝區其餘為 0

第 5 題:參數求值順序與副作用

原文問題代碼

int a = 10, b = 20, c = 30;
printf("%d..%d..%d\n", a+b+c, (b = b*2), (c = c*2));

未定義行為分析

C 標準不規定函數參數求值順序。b=b*2 和 c=c*2 的副作用(修改變量)與 a+b+c 的讀取無序列點約束 → 未定義行為。

正確寫法

int a = 10, b = 20, c = 30;
int sum = a + b + c;
b *= 2;
c *= 2;
printf("%d..%d..%d\n", sum, b, c);  // 明確順序,無歧義

序列點與副作用規則速查

原文寫法問題標準做法
void main()非標準,行為未定義int main(void) 或 int main(int argc, char *argv[])
return; 無值返回隨機值給 OSreturn 0/EXIT_SUCCESS 或 return EXIT_FAILURE
錯誤輸出用 stdout混淆正常/錯誤流fprintf(stderr, ...)
無 free 路徑內存洩露所有分配路徑必須配對釋放
表達式序列點位置安全性
a = b + c賦值完成後安全
f(a, b)所有參數求值後、進入函數前參數間無序
a && ba 求值後安全(短路)
a || ba 求值後安全(短路)
a ? b : ca 求值後安全
a , ba 求值後安全(逗號運算符)
i = i++無序列點分隔兩次修改UB
a[i++] = i讀寫 i 無序列點UB

編譯器檢測建議

# GCC/Clang 推薦標誌
-Wall -Wextra -Wsequence-point -Wunsequenced
# 更嚴格
-fsanitize=undefined -fsanitize-undefined-trap-on-error

工程原則總結

  1. main 必須返回 int,使用 EXIT_SUCCESS/FAILURE
  2. 每個 malloc 對應一個 free,所有控制流路徑覆蓋
  3. 拒絕 strncpy,改用 snprintf 或手動保證結尾
  4. 單語句單副作用,避免參數求值順序依賴
  5. 錯誤輸出走 stderr,便於管道重定向
  6. 啟用編譯器警告,視警告為錯誤 (-Werror)

C 語言給予程序員極大自由,也要求極高自律。標準合規不是教條,而是可移植、可維護、安全軟件的基石。

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