一、数组形式的参数会被编译器自动调整为指针
在 C/C++ 函数参数中,数组形式的参数会被编译器自动调整为指针 。
所以:
c
void Fun(int num[6])
等价于:
c
void Fun(int *num)
具体说明:
-
数组大小
6不起作用编译器忽略
6,不会检查传入的数组是否真的至少有 6 个元素。 -
传递的是指针
调用
Fun(arr)时,传递的是数组首元素的地址,不会拷贝整个数组。 -
常见写法
为了表达语义,有时仍会写
int num[6]提示预期数组大小,但实际参数类型仍是int*。 -
验证方法
c
void 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. 数组名会"退化"为指针
在绝大多数表达式中,数组名会被隐式地转换为指向其首元素的指针。这个行为叫做 "数组退化"。
例如:
c
int 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)); // 输出 8(64位系统)或 4(32位系统)
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;
}
输出:
text
sizeof(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 个元素的数组",但编译器并不检查这个约束。