函數參數傳遞本質是拷貝實參的值。若要在被調函數中修改主調函數的變量,必須傳遞該變量的地址(指針)。
void ModifyValue(int *p) {
*p = 100; // 解引用修改指向的內存
}
int main() {
int a = 9;
ModifyValue(&a); // 傳遞 a 的地址
printf("%d\n", a); // 100
}
關鍵:形參 p 是實參 &a 的拷貝,但 *p 和 a 指向同一內存單元。
若要在函數內修改主調函數中的指針變量的指向,需傳遞指針的地址(二級指針)。
// 題目:使 main 中指針 p 指向合法整型單元
// 選項 A
void fun(int *q) { int s; q = &s; } // 錯:q 是拷貝,修改不影響 p;s 為局部變量,函數返回後失效
// 選項 B
void fun(int **q) { int s; *q = &s; } // 錯:*q 修改了 p 的指向,但指向棧上局部變量 s,函數返回成懸空指針
// 選項 C (正確)
void fun(int **q) { *q = (int*)malloc(sizeof(int)); } // 正確:malloc 分配堆內存,生命週期由程序員控制,需 free
// 選項 D
void fun(int *q) { q = (int*)malloc(sizeof(int)); } // 錯:q 是一級指針拷貝,修改不影響 p
main: fun(int **q):
p ──────> ? q ──────> p (main中p的地址)
*q = malloc() --> 堆內存 0x12345678
修改 *q 即修改 p 的值
main 返回後: p ──────> 0x12345678 (合法堆內存)
同理可推:修改二級指針的指向需三級指針參數。實際工程中極少超過二級。
| 目標 | 參數類型 | 調用示例 | 函數內操作 |
|---|---|---|---|
| 修改普通變量值 | int * | fun(&a) | *p = val; |
| 修改一級指針指向 | int ** | fun(&p) | *p = malloc(...); |
| 修改二級指針指向 | int *** | fun(&pp) | *pp = malloc(...); |
| 輸出動態數組 | int ** 或 int *+長度 | fun(&arr, &n) | *arr = malloc(n*sizeof(int)); |
void fun(const int *p) 承諾不修改指向值,void fun(int *const p) 承諾不修改指針本身(僅對形參生效,實參不受影響)。