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

C語言指針原理(四十七):內存洩露的三種經典模式與鏈表演示

     編輯:關於C

內存洩露是 C/C++ 程序最常見的嚴重缺陷。本文總結內存洩露的三大經典模式,並通過鏈表操作代碼逐一演示,幫助開發者建立敏銳的洩露嗅覺。

模式一:垃圾內存——鏈表斷鏈導致節點不可達

場景:遍歷刪除鏈表時,誤將中間節點的 next 置 NULL,導致後續節點與頭節點失去聯系,無法被後續釋放循環訪問到。

// 錯誤代碼片段
for (mytempnd = mylist->next; mytempnd; mytempnd = mytempnd->next) {
    if (++j > 3) { mytempnd->next = NULL; break; } // 斷開鏈表
}
for (mytempnd = mylist->next; mytempnd; mytempnd = mytempnd->next) {
    free(mytempnd); // 僅能釋放前 4 個節點,後 6 個成為垃圾
}

後果:後 6 個節點內存永久洩露,程序運行越久可用內存越少。

模式二:懸空指針——釋放內存後指針未置空

場景:同上文(第 48 篇),刪除部分鏈表節點但未更新前驅節點的 next,導致前驅指針指向已釋放內存。

隱患:後續誤解引用導致數據損壞、崩潰或安全漏洞。

模式三:共享內存錯誤釋放——多指針共享同一塊內存,一處釋放導致其它指針懸空

場景:多個鏈表節點的 data 指向同一動態分配字符串,刪除其中一個節點時 free(data),其他節點的 data 瞬間變懸空。

對策:引用計數、深拷貝、明確所有權歸屬。

正常鏈表操作基準代碼

// 構建 10 節點鏈表
mynode *mylist = initlist();
mynode *mytempnd = mylist;
for (int i = 0; i < 10; i++) mytempnd = addnode(mytempnd, i, 20+i);
// 正確輸出
for (mytempnd = mylist->next; mytempnd; mytempnd = mytempnd->next)
    printf("id:%d, age:%d\n", mytempnd->number, mytempnd->age);
// 正確銷毀:雙指針法,保存 next 再 free 當前
for (mytempnd = mylist->next; mytempnd; ) {
    mynode *next = mytempnd->next;
    free(mytempnd);
    mytempnd = next;
}
free(mylist);

核心防洩漏原則

  1. 申請與釋放配對:每個 malloc/calloc/realloc 必須有對應的 free,且只能 free 一次。
  2. 數據結構完整性:修改指針(如 next)時,確保不會切斷對其他有效內存的唯一訪問路徑。
  3. 共享內存協議:引用計數或明確所有權,禁止「誰用誰釋放」的隨意行為。
  4. 釋放即置空:free(p); p = NULL; 防懸空指針二次傷害。
  5. 工具化檢測:編譯加 -fsanitize=address,運行時用 Valgrind/ASan 定位洩露點。

運行對比

正常銷毀輸出 10 行 delete id:0..9;垃圾模式僅輸出前 4 行刪除信息,後 6 節點靜默洩露;懸空/共享模式程序雖能運行但埋下定時炸彈。

總結

內存洩露本質是內存塊失去所有可達引用(垃圾)或引用指向無效內存(懸空/共享錯誤)。養成「分配即規劃釋放路徑、修改指針即檢查可達性、共享即建立協議」的編程習慣,配合靜態分析與動態檢測工具,是寫出健壯 C 代碼的必經之路。

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