函数形参传数组

张开发
2026/4/18 1:55:15 15 分钟阅读

分享文章

函数形参传数组
一、数组形式的参数会被编译器自动调整为指针在 C/C 函数参数中数组形式的参数会被编译器自动调整为指针。所以cvoid Fun(int num[6])等价于cvoid Fun(int *num)具体说明数组大小6不起作用编译器忽略6不会检查传入的数组是否真的至少有 6 个元素。传递的是指针调用Fun(arr)时传递的是数组首元素的地址不会拷贝整个数组。常见写法为了表达语义有时仍会写int num[6]提示预期数组大小但实际参数类型仍是int*。验证方法cvoid Fun(int num[6]) { printf(%zu\n, sizeof(num)); // 输出指针大小如 8 字节不是 6*4 }例外情况只有在函数参数中才会这样。如果是int num[6]作为局部变量那么sizeof(num)就是整个数组的大小。二、为什么等价等价的根本原因是为了效率和避免不必要的数组拷贝。具体来说有以下几个关键点1. 值传递的代价问题在 C/C 中函数参数默认是值传递。这意味着如果你真的把整个数组传给函数就需要拷贝数组中的每一个元素。如果数组很大比如int num[10000]每次调用函数都要拷贝 10000 个int内存和时间开销会非常大。为了解决这个问题C 语言的设计者决定永远不直接传递数组本身。2. 数组名会退化为指针在绝大多数表达式中数组名会被隐式地转换为指向其首元素的指针。这个行为叫做数组退化。例如cint arr[6] {1,2,3,4,5,6}; int *p arr; // arr 退化成 arr[0]当你在函数参数中写int num[6]时编译器会自动将它重写为int *num。C 继承了这一规则为了兼容 C 语言。3. 标准文档明确规定C 标准如 C99 §6.7.6.3明确指出声明函数参数为“类型 数组名[大小]”时它会被调整为“类型 * 数组名”。所以void Fun(int num[6])→ 编译器看到int num[6]作为参数 → 调整成int *num调用时Fun(arr)→arr退化为arr[0]→ 传给num的是指针地址最终效果函数内部操作num[i]其实是通过指针 偏移量访问原始数组的元素。4. 如果不等价会怎样如果数组参数真的是按值传递整个数组每次函数调用都会拷贝整个数组效率极低。无法通过函数修改原数组的内容因为操作的是拷贝。但这正是 C 语言缺乏引用传递C 有引用时的折中方案传指针即可修改原数组。5. 验证示例c#include stdio.h void Fun(int num[6]) { printf(sizeof(num) %zu\n, sizeof(num)); // 输出 864位系统或 432位系统 printf(sizeof(int*) %zu\n, sizeof(int*)); // 和上面一样 num[0] 100; // 修改的是原数组 } int main() { int arr[6] {0}; printf(sizeof(arr) %zu\n, sizeof(arr)); // 输出 24 (6 * 4) Fun(arr); printf(arr[0] %d\n, arr[0]); // 输出 100说明修改了原数组 return 0; }输出textsizeof(arr) 24 sizeof(num) 8 sizeof(int*) 8 arr[0] 100可以看到函数内部的sizeof(num)是指针大小不是数组大小。修改num[0]会影响外部的arr[0]。总结等价的原因设计选择避免数组拷贝提高效率。自动退化数组参数被编译器自动调整为指针。语义统一无论你写int num[6]、int num[]还是int *num最终参数类型都是int*。所以写int num[6]只是语法糖主要作用是给代码阅读者一个提示“这个函数期望传入一个至少有 6 个元素的数组”但编译器并不检查这个约束。

更多文章