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

C語言指標傳遞深度解析:從值傳遞到二級指標

     編輯:關於C語言

為何需要指標傳遞?

C 語言採用值傳遞:函數參數為實參副本。若需在函數內修改呼叫端變數,必須傳遞其位址(指標)。若需修改指標本身(如分配記憶體並回傳),則需傳遞指標的指標(二級指標)。

經典案例:交換兩數

void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

int main() {
    int m = 5, n = 10;
    printf("m=%d, n=%d\n", m, n);
    swap(&m, &n);
    printf("m=%d, n=%d\n", m, n);  // 輸出 m=10, n=5
    return 0;
}

傳遞位址 &m, &n,函數通過解引用修改原變數。

傳遞指向常量的指標

不希望函數修改數據時,用 const 保護:

void passconstant(const int *num1, int *num2) {
    *num2 = *num1;  // OK:讀取 num1,修改 num2
    // *num1 = 100; // 編譯錯誤:嘗試修改 const 數據
}

int main() {
    const int a = 100;
    int b = 5;
    passconstant(&a, &b);
    printf("a=%d, b=%d\n", a, b);  // a=100, b=100
    return 0;
}

堆與棧的區別(記憶體分配基礎)

特性棧堆
分配方式編譯器自動程式設計師手動
釋放方式自動(函數返回)手動 free,否則洩漏
生存週期函數執行期間手動釋放前持續有效
大小限制較小(Windows 典型 1-2MB)受限於虛擬記憶體,較大
分配效率極快較慢,易產生碎片
存儲內容區域變數、參數、返回位址動態分配物件

常見錯誤:返回區域變數指標

// 錯誤示範
int *allocateArray(int size, int value) {
    int arr[size];  // 區域陣列,棧上分配
    for (int i = 0; i < size; i++) arr[i] = value;
    return arr;     // 返回棧地址,函數返回後失效!
}

正確做法 1:動態分配 + 呼叫端釋放

int *allocateArray(int size, int value) {
    int *arr = (int *)malloc(size * sizeof(int));
    for (int i = 0; i < size; i++) arr[i] = value;
    return arr;  // 堆記憶體,持續有效
}

int main() {
    int *vec = allocateArray(5, 45);
    for (int i = 0; i < 5; i++) printf("%d\n", vec[i]);
    free(vec);  // 呼叫端負責釋放
    return 0;
}

正確做法 2:呼叫端分配,函數填充

int *allocateArray(int *arr, int size, int value) {
    if (arr) for (int i = 0; i < size; i++) arr[i] = value;
    return arr;  // 為鏈式調用返回指標
}

int main() {
    int *vec = (int *)malloc(5 * sizeof(int));
    allocateArray(vec, 5, 45);
    // 使用 vec...
    free(vec);
    return 0;
}

傳遞二級指標:修改指標本身

函數內分配記憶體並將指標回傳給呼叫端:

void allocateArray(int **arr, int size, int value) {
    *arr = (int *)malloc(size * sizeof(int));
    if (*arr) for (int i = 0; i < size; i++) *(*arr + i) = value;
}

int main() {
    int *vec = NULL;
    allocateArray(&vec, 5, 45);
    for (int i = 0; i < 5; i++) printf("%d\n", vec[i]);
    free(vec);
    return 0;
}

關鍵:&vec 傳遞指標位址,函數通過 *arr 解引用修改原指標值。

實戰:二叉樹遞歸建立與二級指標

遞歸函數需修改父節點的 lchild/rchild 指標,故須傳遞二級指標:

typedef struct Node {
    char ch;
    struct Node *lchild, *rchild;
} Node, *BTree;

void CreateTree(Node **pTree) {
    char ch;
    scanf(" %c", &ch);
    if (ch == '#') {
        *pTree = NULL;
    } else {
        *pTree = (Node *)malloc(sizeof(Node));
        (*pTree)->ch = ch;
        CreateTree(&(*pTree)->lchild);  // 傳遞左子指標位址
        CreateTree(&(*pTree)->rchild);  // 傳遞右子指標位址
    }
}

int main() {
    BTree root = NULL;
    CreateTree(&root);  // 傳遞根指標位址
    // 後續遍歷...
    return 0;
}

&(*pTree)->lchild 即「指向當前節點左子指標的指標」,遞歸層層傳遞,最終在葉子位置建立節點並掛鏈到父節點。

總結

  1. 需修改實參值 → 傳一級指標
  2. 需修改實參指標(如分配記憶體) → 傳二級指標
  3. 區分棧/堆記憶體,勿返回區域變數位址
  4. 善用 const 表達「只讀」語意,編譯器協助防錯

指標傳遞是 C 語言核心機制,掌握其層級關係與記憶體語意,能寫出正確、高效、安全的系統級代碼。

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