「C 語言參數傳遞只有值傳遞。」函數調用時,實參的值被拷貝給形參。形參是函數內部的局部變量,修改不影響實參。
void modify(int x) {
x = 20; // 修改形參副本
}
int main() {
int a = 10;
modify(a);
printf("%d\n", a); // 輸出 10,a 未變
return 0;
}
若需在函數內修改實參,傳遞實參地址,函數通過解引用修改原內存。
void modify(int *px) {
*px = 20; // 解引用修改原變量
}
int main() {
int a = 10;
modify(&a); // 傳遞地址
printf("%d\n", a); // 輸出 20
return 0;
}
這是值傳遞指針值,實現了引用語義。標準庫 scanf("%d", &n) 同理。
數組名作為實參時退化為首元素指針,形參接收指針。函數內可修改數組內容。
// 三種等價聲明
void process(int arr[]);
void process(int arr[10]); // 10 被忽略
void process(int *arr);
void process(int *arr) {
arr[0] = 99; // 修改原數組首元素
// arr = NULL; // 僅修改局部指針副本,不影響實參
}
int main() {
int a[5] = {1,2,3,4,5};
process(a);
printf("%d\n", a[0]); // 99
return 0;
}
⚠️ 函數內 sizeof(arr) 返回指針大小,非數組大小。需額外傳遞長度參數。
void foo(int a, double b, char *str); // 聲明
foo(10, 3.14, "hello"); // 調用:實參類型須與形參兼容
// 隱式轉換:int→double, 數組→指針, 字面量→const char*
嚴格匹配參數個數、順序、類型。舊式 K&R 風格已廢棄,必須用原型聲明。
int square(int x) {
return x * x; // 返回值拷貝給調用者
}
// 調用
int result = square(5); // result = 25
printf("%d\n", square(5)); // 直接用作表達式
// ❌ 錯誤:返回局部變量地址
int* bad() {
int x = 10;
return &x; // 棧內存函數返回即失效
}
// ✅ 正確:返回靜態/全局/堆內存地址
int* good_static() {
static int x = 10;
return &x; // 靜態存儲區,生命週期全程
}
int* good_heap() {
return malloc(sizeof(int)); // 調用者負責 free
}
struct Point { int x, y; };
struct Point make_point(int x, int y) {
return (struct Point){x, y}; // 復合字面量,返回值拷貝
}
| 模式 | 示例 | 優點 | 缺點 |
|---|---|---|---|
| 輸出參數 (指針) | void divmod(int a, int b, int *q, int *r) | 標準、高效 | 調用繁瑣 |
| 返回結構體 | struct DivMod { int q, r; }; | 清晰、類型安全 | 拷貝開銷 (小結構可忽略) |
| 全局/靜態緩衝區 | char *strtok(...) | 簡單 | 非線程安全、可重入性差 |