為什麼 C 語言中數組作為函數參數傳遞時,實際傳遞的是首元素地址(指針),而不是按值傳遞整個數組副本?
以 x86 cdecl 調用約定為例,函數調用時棧幀結構:
高地址
┌─────────────────┐
│ 參數 n (arg4) │ ← 最後壓棧
├─────────────────┤
│ 參數 3 (arg3) │
├─────────────────┤
│ 參數 2 (arg2) │
├─────────────────┤
│ 參數 1 (arg1) │ ← 最先壓棧
├─────────────────┤
│ 返回地址 (PC) │
├─────────────────┤
│ 舊 EBP 值 │ ← EBP 基址指針
├─────────────────┤
│ 保存的寄存器 │
├─────────────────┤
│ 局部變量空間 │ ← ESP 棧頂指針
└─────────────────┘
低地址
void func(int arr[]) { // 等價於 int* arr
printf("sizeof(arr) = %zu\n", sizeof(arr)); // 輸出 4 或 8(指針大小)
arr[0] = 999; // 修改原數組內容
}
int main() {
int a[100] = {0};
printf("sizeof(a) = %zu\n", sizeof(a)); // 輸出 400(數組完整大小)
func(a);
printf("a[0] = %d\n", a[0]); // 輸出 999,原數組被修改
}
struct Arr { int data[100]; }; 結構體按值傳遞會複製整個內容std::array 或 std::vector(需注意拷貝開銷)memcpy 到局部數組數組退化為指針是 C 語言為了效率和棧安全做出的核心設計決策,這也是 C/C++ 高性能特性的基石之一。