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

C 語言通用堆疊實作:結構體資料出堆疊異常的根因與修正

     編輯:關於C語言

問題背景

使用通用堆疊庫(Piles.h/.c)存放 Point 結構體時,整數測試正常,但結構體連續 pop 卻總顯示最後壓入的資料。程式在 Linux GCC 下編譯通過,執行結果如下:

Empiler le point (0.000000, 0.000000)
Empiler le point (1.000000, 1.000000)
Empiler le point (2.000000, 2.000000)
Empiler le point (3.000000, 3.000000)
Depiler le point (3.000000, 3.000000)  // 重複四次!
Depiler le point (3.000000, 3.000000)
Depiler le point (3.000000, 3.000000)
Depiler le point (3.000000, 3.000000)

程式碼關鍵片段

堆疊介面

typedef struct _pile *Pile;
void empiler(Pile, void *element, ExceptionPile *);  // push
void depiler(Pile, ExceptionPile *);                  // pop
void *sommet(Pile, ExceptionPile *);                  // top

測試主程式

Point *p1 = malloc(sizeof *p1);
for (i = 0; i < 4; i++) {
    p1->x = (float)i;
    p1->y = (float)i;
    empiler(p_nouveau, p1, &exp);  // 每次傳入同一指標!
}
for (i = 0; i < 4; i++) {
    p1 = sommet(p_nouveau, &exp);
    printf("Depiler le point (%f, %f)\n", p1->x, p1->y);
    depiler(p_nouveau, &exp);
}

根因分析

經典指標陷阱:迴圈中重複使用同一個 p1 指標,每次 push 存入的都是同一個記憶體位址。迴圈結束時,該記憶體保留最後賦值(3,3),堆疊四個節點全指向同一塊記憶體,故 pop 時全讀到 (3,3)。

整數測試之所以「正常」,是因為 element = (int*)i 將整數值強轉為指標,每次傳入的「指標值」不同,實際上是把整數編碼在指標裡,而非真正指向獨立記憶體。

修正方案

for (i = 0; i < 4; i++) {
    Point *p1 = malloc(sizeof(Point));  // 每次新建節點!
    p1->x = (float)i;
    p1->y = (float)i;
    empiler(p_nouveau, p1, &exp);
}
// pop 時記得 free
for (i = 0; i < 4; i++) {
    Point *p1 = sommet(p_nouveau, &exp);
    printf("Depiler le point (%f, %f)\n", p1->x, p1->y);
    depiler(p_nouveau, &exp);
    free(p1);  // 釋放記憶體
}

術語對照

法文中文英文
pile堆疊stack
empiler壓入push
depiler彈出pop
sommet堆疊頂top
element元素element

通用資料結構以 void* 存放任意型別時,呼叫端必須確保每個元素擁有獨立生命週期。此問題非庫本身缺陷,屬於 C 語言指標語意的常見誤區。

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