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

C語言函數參數傳遞:值傳遞與指針模擬引用

     編輯:C 語言入門

核心認知:C語言只有值傳遞

C++ 有引用(&),C 語言沒有。函數參數始終是實參的副本,形參與實參佔據不同內存地址。這是理解一切參數傳遞問題的基石。

一、值傳遞的本質

void foo(int x) {
    x = 10;  // 修改的是副本
}
int main() {
    int a = 5;
    foo(a);  // a 仍為 5
}

形參 x 是實參 a 的值拷貝,兩者地址不同,修改不影響原變量。

二、指針傳遞:傳遞地址的值

void foo(int *p) {
    *p = 10;  // 通過地址修改原變量
}
int main() {
    int a = 5;
    foo(&a);  // a 變為 10
}

雖然指針 p 也是副本,但它存儲的是 a 的地址。解引用 *p 直接操作原內存,達到「修改外部變量」的效果。

三、二級指針:修改指針本身

若需在函數內修改指針變量本身(如動態分配內存並返回),必須傳遞指針的地址:

void initTree(Tree **T) {  // 二級指針
    char ch = getchar();
    if (ch == '#') { *T = NULL; }
    else {
        *T = (Tree*)malloc(sizeof(Tree));  // 給實參指針分配內存
        (*T)->t = ch;
        initTree(&(*T)->lchild);  // 遞歸傳遞左孩子地址
        initTree(&(*T)->rchild);
    }
}

四、錯誤對比:一級指針無法構建樹

// 錯誤寫法
void initTree(Tree *T) {  // 一級指針
    if (ch == '#') { T = NULL; }  // 修改的是副本!
    else {
        T = (Tree*)malloc(sizeof(Tree));  // 給副本分配內存
        T->t = ch;
        initTree(T->lchild);  // 遞歸傳遞副本的孩子指針
        initTree(T->rchild);
    }
}

後果: 每層遞歸操作的都是指針副本,申請的內存無法連接成樹,函數返回後根指針仍為野指針/NULL,內存洩漏。

五、正確寫法解析

void initTree(Tree **T) {
    // ...
    *T = (Tree*)malloc(sizeof(Tree));  // 關鍵:解引用賦值,修改實參指向
    // ...
    initTree(&(*T)->lchild);  // 傳遞左孩子指針的地址
}
  • Tree **T:接收 Tree* 的地址
  • *T:解引用得到實參指針本身
  • &(*T)->lchild:取左孩子指針的地址(二級指針)

通用模式總結

需求形參類型調用方式函數內操作
只讀數值int xfoo(a)直接用 x
修改數值int *pfoo(&a)*p = val
修改指針(如分配內存)int **pfoo(&ptr)*p = malloc(...)
修改結構體指針成員Node **pfoo(&root->child)*p = new_node

記住鐵律

C語言只有值傳遞。任何想在函數內修改的外部對象,必須傳遞其地址,函數以對應層級指針接收。

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