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

C語言指針原理(四十九):共享內存導致的內存洩露與懸空指針演示

     編輯:關於C

本文通過具體代碼演示內存洩露的第三種常見場景:多個指針共享同一塊內存,因其中一個指針釋放該內存,導致其他指針成為懸空指針。這是鏈表等動態數據結構中極易犯的錯誤。

場景構建

  • 創建一個包含 3 個節點的鏈表。
  • 所有節點的 data 指釵指向同一塊動態分配的字符串內存 (mydata)。
  • 遍歷輸出驗證共享正常。
  • 錯誤操作:刪除最後一個節點時,同時 free(oldtmpnd->data) 釋放了共享內存。
  • 前兩個節點的 data 指針隨即指向已釋放內存,成為懸空指針。

完整演示代碼

#include 
#include 
#include 

typedef struct listnode mynode;
struct listnode {
    mynode *next;
    char *data;
    int number;
    int age;
};

mynode *addnode(mynode *prevnd, int number, int age, char *data) {
    mynode *ndtemp = (mynode*)malloc(sizeof(mynode));
    prevnd->next = ndtemp;
    ndtemp->number = number;
    ndtemp->age = age;
    ndtemp->data = data; // 共享同一 data 指針
    ndtemp->next = NULL;
    return ndtemp;
}

mynode *initlist() {
    mynode *temp = (mynode*)malloc(sizeof(mynode));
    temp->number = 0; temp->age = 0; temp->data = NULL; temp->next = NULL;
    return temp;
}

int main() {
    mynode *mylist = initlist();
    mynode *mytempnd = mylist;
    char *mydata = (char*)malloc(100);
    const char *strsrc = "helloworld";
    strcpy(mydata, strsrc);

    // 構建 3 個節點,共享 mydata
    for (int i = 0; i < 3; i++) {
        mytempnd = addnode(mytempnd, i, 20+i, mydata);
    }

    // 輸出驗證
    for (mytempnd = mylist->next; mytempnd != NULL; mytempnd = mytempnd->next) {
        printf("id:%d, age:%d, data:%s\n", mytempnd->number, mytempnd->age, mytempnd->data);
    }

    printf("-------------------------\n");

    // 錯誤刪除:僅刪除最後一個節點,但釋放了共享的 data
    mynode *oldtmpnd;
    for (mytempnd = mylist->next; mytempnd != NULL; ) {
        oldtmpnd = mytempnd;
        mytempnd = mytempnd->next;
        if (mytempnd == NULL) { // 最後一個節點
            printf("delete id:%d\n", oldtmpnd->number);
            free(oldtmpnd->data); // 釋放共享內存!
            free(oldtmpnd);
        }
    }
    // 此時 mylist->next 和 mylist->next->next 的 data 均為懸空指針
    return 0;
}

運行結果

id:0, age:20, data:helloworld
id:1, age:21, data:helloworld
id:2, age:22, data:helloworld
-------------------------
delete id:2

錯誤分析與後果

  1. 內存洩露假象:實際上共享內存被提前釋放,而非洩露;但殘留指針指向無效區域。
  2. 懸空指針隱患:後續訪問前兩個節點的 data 會導致未定義行為(數據損壞、程序崩潰、安全漏洞)。
  3. free 語義:free 僅標記內存可重用,數據可能暫時殘留,但隨時可能被覆蓋,不可依賴。

正確處理策略

  • 引用計數:共享內存附帶計數器,最後一個引用者釋放時才真正 free。
  • 所有權轉移:明確規定哪個節點擁有 data 的所有權,僅擁有者負責釋放,其他節點持有非所有權指針(或複製數據)。
  • 深拷貝:每個節點分配獨立 data 並 strcpy,各自管理生命周期(空間換安全)。

總結

共享內存是優化性能的常用手段,但必須建立清晰的所有權語義與生命周期管理機制。C 語言無 GC,程序員需自行確保「誰分配、誰釋放」或引入引用計數/智能指針模式,否則極易產生難以排查的懸空指針與內存錯誤。

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