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

C 語言鏈結串列找最小值,程式跑起來卻當機?指標邏輯錯在哪裡

     編輯:程式設計綜合問答

現象:編譯通過,執行卻段錯誤或輸出亂碼

寫了一個「輸入 n 個數字建立鏈結串列,遍歷找出最小值節點」的 C 程式,邏輯看起來沒問題,但執行時要么直接 Segmentation Fault,要么印出一堆亂碼。重點錯誤在建立串列的迴圈與指標操作上。

原始碼關鍵錯誤分析

head = (EXAMPLE*)malloc(sizeof(EXAMPLE));
pre = head;
for(i = 1; i <= n; i++) {
    printf("input = ? ");
    scanf("%d", &pre->input);          // 寫入 pre 指向的節點
    pre->keyword = i;
    p = (EXAMPLE*)malloc(sizeof(EXAMPLE)); // 配置「下一個」節點
    pre->next = p;                     // 串接
    pre = p;                           // pre 移到新節點
}
pre = NULL; // ❌ 致命錯誤:只把區域變數 pre 設 NULL,串列尾巴沒斷開!

三大核心問題

  1. 串列尾節點 next 未設為 NULL:迴圈結束時,最後配置的節點 p 的 next 欄位是未初始化的垃圾值,非 NULL。後續 while(po) 遍歷不會在正確位置停下,導致存取非法記憶體 → 段錯誤。
  2. 最後一個節點資料未寫入:迴圈邏輯是「先寫入 pre,再配置 p」,導致第 n 次迴圈配置的節點 完全沒被寫入資料,卻被串在串列尾端,遍歷時會印出亂碼。
  3. pre = NULL 完全無效:pre 只是區域指標變數,設為 NULL 不會影響串列結構,真正的尾節點 next 依然指向垃圾位址。

正確的建立串列邏輯

head = (EXAMPLE*)malloc(sizeof(EXAMPLE));
if (!head) { printf("no memory\n"); return 0; }

printf("input = ? ");
scanf("%d", &head->input);
head->keyword = 1;
head->next = NULL;          // ✅ 關鍵:明確終止

pre = head;
for (i = 2; i <= n; i++) {  // 從 2 開始,head 已處理
    p = (EXAMPLE*)malloc(sizeof(EXAMPLE));
    if (!p) { printf("no memory\n"); return 0; }

    printf("input = ? ");
    scanf("%d", &p->input); // ✅ 直接寫入新節點 p
    p->keyword = i;
    p->next = NULL;         // ✅ 每個新節點 next 歸零

    pre->next = p;          // 串接
    pre = p;                // 移動 pre
}

找最小值遍歷的正確寫法

pMin = head;
p = head->next;             // 從第二個節點開始比較
while (p) {
    if (pMin->input > p->input)
        pMin = p;
    p = p->next;
}
printf("min : %d %d\n", pMin->keyword, pMin->input);

避坑指南:C 鏈結串列三大鐵律

  1. malloc 後立即檢查回傳值是否為 NULL,失敗要釋放已配置記憶體並退出。
  2. 每個新節點配置完,馬上初始化所有欄位(含 next = NULL),別留給後面統一處理。
  3. 串列尾節點的 next 必須明確設為 NULL,這是遍歷終止條件的唯一保證。

完整可執行範例

#include 
#include 

struct example {
    int input;
    int keyword;
    struct example* next;
};
typedef struct example EXAMPLE;

int main(void) {
    EXAMPLE *head, *p, *pre, *pMin;
    int n, i = 1;

    printf("n = ? ");
    scanf("%d", &n);
    if (n <= 0) return 0;

    head = malloc(sizeof(EXAMPLE));
    if (!head) { printf("no memory\n"); return 0; }

    printf("input = ? ");
    scanf("%d", &head->input);
    head->keyword = i;
    head->next = NULL;
    i++;

    pre = head;
    for (; i <= n; i++) {
        p = malloc(sizeof(EXAMPLE));
        if (!p) { printf("no memory\n"); return 0; }
        printf("input = ? ");
        scanf("%d", &p->input);
        p->keyword = i;
        p->next = NULL;
        pre->next = p;
        pre = p;
    }

    // 列印驗證
    for (p = head; p; p = p->next)
        printf("%d %d\n", p->keyword, p->input);

    // 找最小值
    pMin = head;
    for (p = head->next; p; p = p->next)
        if (pMin->input > p->input) pMin = p;

    printf("min : %d %d\n", pMin->keyword, pMin->input);

    // 釋放記憶體(良好習慣)
    for (p = head; p; ) {
        EXAMPLE *tmp = p;
        p = p->next;
        free(tmp);
    }
    return 0;
}

結語

指標操作最怕「以為串好了,其實尾巴沒斷」。每次 malloc 完馬上把 next 歸零,建立節點時直接寫入新節點而非舊節點,這兩個習慣能消滅 90% 的鏈結串列 Bug。下次寫鏈結串列,請在腦中預演:「配置 → 初始化 → 串接 → 移動」,一步不漏,程式就會穩如磐石。

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