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

C 語言鏈表遍歷函數重複調用仍能正確輸出的原理解析

     編輯:程式設計疑難解答

現象描述

代碼中連續兩次調用 show_all(head),第二次仍能正常打印所有節點數據。疑問:show_all 內部將 head 指針移動至鏈表末尾(NULL),為何第二次調用不受影響?

核心原因:值傳遞機制

void show_all(st* head) {  // 參數是指針的副本
    while (head != NULL) {
        printf("%d,%f\n", head->num, head->score);
        head = head->pnext;  // 修改的是副本,不影響實參
    }
}
  • 實參:main 中的 head 指針,指向鏈表頭節點。
  • 形參:show_all 的 head 參數,是實參的拷貝(同樣指向頭節點)。
  • 函數內操作:修改形參 head 指向下一節點,實參 main::head 保持不變,仍指向頭節點。

內存模型圖解

main() 棧幀:           show_all() 棧幀 (第 1 次調用):
head ──────┐            head ──────┐
           │                   │
           ▼                   ▼
       [節點 1] → [節點 2] → ... → [節點 5] → NULL
       (堆內存,雙方共享)

第二次調用時,形參再次獲得實參的拷貝(仍指向頭節點),遍歷邏輯完全獨立。

代碼修正與完善

原代碼存在語法錯誤(缺少 *、頭文件不全),修正版:

#include <stdio.h>
#include <stdlib.h>

struct student {
    int num;
    float score;
    struct student *pnext;
};
typedef struct student st;

void add(st **phead, int inum, float iscore) {
    st *newnode = (st*)malloc(sizeof(st));
    newnode->num = inum;
    newnode->score = iscore;
    newnode->pnext = NULL;

    if (*phead == NULL) {
        *phead = newnode;
    } else {
        st *p = *phead;
        while (p->pnext != NULL) p = p->pnext;
        p->pnext = newnode;
    }
}

void show_all(st *head) {  // 值傳遞:接收指針副本
    while (head != NULL) {
        printf("%d, %.2f\n", head->num, head->score);
        head = head->pnext;  // 僅移動局部副本
    }
}

int main() {
    st *head = NULL;
    add(&head, 1, 20.0);
    add(&head, 2, 30.0);
    add(&head, 3, 40.0);
    add(&head, 4, 50.0);
    add(&head, 5, 60.0);
    
    show_all(head);  // 第一次遍歷
    printf("---\n");
    show_all(head);  // 第二次遍歷,head 仍指向頭節點
    return 0;
}

對比:若需修改頭指針

若函數需要修改實參指針(如刪除頭節點),必須傳遞指針的指針或引用:

// C 風格:二級指針
void delete_head(st **phead) {
    if (*phead) {
        st *tmp = *phead;
        *phead = (*phead)->pnext;  // 修改實參指向
        free(tmp);
    }
}

// C++ 風格:引用
void delete_head(st *&head) {
    if (head) {
        st *tmp = head;
        head = head->pnext;
        delete tmp;
    }
}

總結

  • C 語言採用值傳遞,指針作為參數時傳遞的是地址值的副本。
  • 函數內修改形參指針不影響實參指針,僅影響副本指向。
  • 若需修改實參指針本身,必須傳遞指針的地址(二級指針)或使用 C++ 引用。
  • 此特性保證了 show_all 等只讀遍歷函數的安全性與可重入性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved