定義與核心機制
- 形參 (Formal Parameter): 函式定義/宣告中括號內的變數,僅在函式內部可見,佔用棧幀空間。
- 實參 (Actual Argument): 調用點傳入的表達式/變數/常數,求值後將結果複製給對應形參。
- C 語言唯一調用約定:傳值調用 (Call by Value)。 實參值被複製,函式內修改形參不影響實參原變數。
經典範例
#include <stdio.h>
void swap_val(int a, int b) { // 形參
int t = a; a = b; b = t;
printf("swap_val 內: a=%d, b=%d\n", a, b);
}
void swap_ptr(int *pa, int *pb) { // 形參為指標,模擬傳址
int t = *pa; *pa = *pb; *pb = t;
}
int main() {
int x = 3, y = 5; // 實參變數
printf("調用前: x=%d, y=%d\n", x, y);
swap_val(x, y); // 實參為 x, y (值 3, 5 複製給形參 a, b)
printf("swap_val 後: x=%d, y=%d\n", x, y); // x,y 不變
swap_ptr(&x, &y); // 實參為 &x, &y (位址值複製給形參 pa, pb)
printf("swap_ptr 後: x=%d, y=%d\n", x, y); // x,y 交換成功
return 0;
}
特殊情況:陣列實參退化為指標
void func(int arr[]) { // 等價於 void func(int *arr)
printf("sizeof(arr) = %zu\n", sizeof(arr)); // 印出指標大小 (4/8),非陣列大小
arr[0] = 999; // 修改原陣列首元素
}
int main() {
int a[5] = {1,2,3,4,5};
printf("sizeof(a) = %zu\n", sizeof(a)); // 20 (5*4)
func(a); // 實參 a 退化為 int* (首元素位址)
printf("a[0] = %d\n", a[0]); // 999
return 0;
}
- 若需在函式內獲得陣列長度,**必須額外傳遞長度參數** 或使用結構體包裹 (柔性陣列成員)。
- 多維陣列退化:`int a[3][4]` → `int (*)[4]` (指向含 4 個 int 陣列的指標),第二維度長度必須在形參聲明中給出。
可變參數 (``)
#include <stdarg.h>
#include <stdio.h>
void print_ints(int count, ...) {
va_list ap;
va_start(ap, count);
for (int i = 0; i < count; ++i) {
int val = va_arg(ap, int); // 必須知道類型
printf("%d ", val);
}
va_end(ap);
printf("\n");
}
int main() {
print_ints(5, 10, 20, 30, 40, 50);
return 0;
}
最佳實踐
- 標量參數預設 `const` 形參 (`void func(const int x)`) 表示不修改,若需修改用指標 (`void func(int *px)`)。
- 大型結構體傳遞:用 `const struct Big *` 避免棧拷貝開銷。
- 陣列參數:聲明為 `void func(const int *arr, size_t n)` 或 `void func(const int arr[static n])` (C99 靜態長度提示)。
- 字串參數:`void func(const char *s)`,約定以 `\0` 結尾。
- 可變參數:僅用於類 `printf` 格式化場景,嚴格檢查格式字串與參數匹配 (`-Wformat`)。