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

C 語言鏈表全域變數傳參陷阱:為何 print 函數中 list 為 NULL?

     編輯:程式設計疑難解答

問題重現

初學者常遇到的經典問題:在 input() 中透過 malloc 建立鏈表節點,指派給全域指標 list,但在 print() 中卻發現 list == NULL。程式碼片段如下:

struct node *list, *p, *r, *q;

void input(struct node *list) {
    // ... 建立節點 ...
    if (list == NULL) list = p;
    else r->link = p;
    r = p;
}

int main() {
    input(list);  // 傳遞 list
    print(list);  // list 仍為 NULL
}

核心原因:一級指標傳值無法修改呼叫端指標

C 語言參數傳遞採呼叫端傳值。input(struct node *list) 接收的是 main 中 list 的副本(同樣指向 NULL)。函式內部修改 list = p 只改變了區域副本,原本的全域 list 仍指向 NULL。

解決方案三種

1. 直接使用全域變數(最簡單)

既然 list 已宣告為全域,函式簽名移除參數,直接操作全域 list:

void input() {
    list = NULL;  // 重置
    for (int i = 0; i < N; i++) {
        p = malloc(sizeof(struct node));
        // ...
        if (list == NULL) list = p;
        else r->link = p;
        r = p;
    }
}

同理 print()、average() 也不需傳參。

2. 傳遞二級指標(指標的指標)

void input(struct node **list) {
    *list = NULL;
    // ...
    if (*list == NULL) *list = p;
    else r->link = p;
}

int main() {
    input(&list);  // 傳遞位址
}

3. 回傳新建立的鏈表頭

struct node* input() {
    struct node *head = NULL;
    // ... 建立 ...
    return head;
}

int main() {
    list = input();
}

補充修正:print 迴圈條件

原碼 while(q->link != NULL) 會漏印最後一個節點,應改為:

while (q != NULL) {
    printf("%d\n", q->score);
    q = q->link;
}

完整修正後程式碼

#include 
#include 

#define N 4

struct node {
    int score;
    struct node *link;
};

struct node *list, *p, *r, *q;

void input() {
    list = NULL;
    for (int i = 0; i < N; i++) {
        p = malloc(sizeof(struct node));
        printf("please input the score of %d\t", i + 1);
        scanf("%d", &p->score);
        p->link = NULL;
        if (list == NULL) list = p;
        else r->link = p;
        r = p;
        printf("數據為%d\n", p->score);
    }
}

void average() {
    int s = 0, i;
    double avg;
    if (list == NULL) { printf("鏈表為空\n"); return; }
    for (i = 0; i < N; i++) {
        s += list->score;
        list = list->link;
    }
    avg = (double)s / N;
    printf("平均值為: %lf\n", avg);
}

void print() {
    printf("順利進入\n");
    if (list == NULL) { printf("這是空鏈表\n"); return; }
    q = list;
    while (q != NULL) {
        printf("%d\n", q->score);
        q = q->link;
    }
}

int main() {
    int ah;
    system("cls");
    while (1) {
        printf("鏈表操作系統:\n1.建立鏈表\n2.輸出數據\n3.求平均數\n");
        scanf("%d", &ah);
        switch (ah) {
            case 1: input(); break;
            case 2: print(); break;
            case 3: average(); break;
            default: printf("wrong!\n"); break;
        }
    }
}

總結

「全域變數 + 一級指標參數」是新手常見誤區。記住:要在函式內修改呼叫端的指標值,必須傳遞指標的位址(二級指標)或直接回傳新指標。若變數已為全域,最簡潔的做法是移除參數直接存取。

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