我有一个以下C代码:
#include <stdio.h>
void test(char a[2])
{
printf("%s", a);
}
int main()
{
char t[5] = {'a', 'b', 'c', 'd'};
test(t);
return 0;
}
输出:abcd
在上面的代码中,我传递一个char指针(大小为5字节的char数组)。但该函数的参数大小为2个字节(char a[2]
)。该计划运作良好。
为什么没有编译错误或警告?这不是说这行void test(char a[2])
期待2个字节的数组吗?
我和我的同事就此进行了辩论。在这种情况下请你开悟。
答案 0 :(得分:3)
编译器忽略函数参数中数组第一维的大小。原型
void test(char a[2]);
相当于
void test(char a[]);
void test(char *a);
或者你可以说编译器只是将void test(char a[2]);
解释为void test(char *a)
同样
void void test2(char a[5][5]);
相当于
void void test2(char a[][5]);
void void test2(char (*a)[5]);
答案 1 :(得分:3)
为什么没有编译错误或警告?这不是故意的吗? line void test(char a 2)期待2个字节的数组?
除非前面有static
,否则2
中的void test(char a[2]);
(由于向后兼容性原因一直追溯到B
language (C's predecessor))只有评论。
换句话说,
void test(char a[2]);
void test(char a[2017]);
void test(char a[]);
void test(char *a);
都是完全等同的声明。
新(C11)允许:
void test(char a[static 2]);
语法允许test
的作者说它真的必须得到一个指向至少 2个项目的数组的指针(更多很好),C11 makes it undefined表示test
的调用者用任何不满足此要求的东西来调用它。但是,你不能指望一个警告。
实际上,在gcc / clang中,只有clang警告并且只有时候(并且tinycc甚至不支持这种扩展语法)
void test(char a[static 2]);
int main()
{
char a[1]={0}, b=0;
test(a); //clang warns about array bounds (gcc doesn't)
test(&(char){'a'}); //no warning
test(&b); //no warning
return 0;
}
答案 2 :(得分:1)
没有。它衰变为char*
。并且print
通过提供地址来终止\0
个char数组。
数组衰减成指向第一个元素的指针。这里第一个元素是char
,因此它衰变为包含第一个元素地址的char*
。
而且,当您传递数组时,编译器会忽略第一个维度。
所以主要的是无法在C 中传递数组。如果你传递一个,那么基本上传递指向第一个元素的指针。由于此处不需要数组大小,因此忽略2
。这就是编译器没有抱怨的原因。
void test(char a[2])
期待2个字节的数组吗?没有。它没有。这就是为什么你甚至可以这样做void test(char a[])
或void test(char a[2017])
。
答案 3 :(得分:1)
作为函数参数的数组会自动转换为指针。所以这个:
void test(char a[2])
与此相同:
void test(char *a)
这是有效的,因为数组在大多数上下文中衰减为指针,包括作为函数的参数。
答案 4 :(得分:1)
当传递数组作为函数参数时,它会立即衰减为指针,数组永远不会实际传递给函数。所以,你得到指针的大小而不是数组。
C11 6.3.2.1/3:
除非它是sizeof运算符或一元&amp;的操作数。 operator,或者是用于初始化数组的字符串文字,a 具有类型''数组类型''的表达式将转换为 带有''指向类型'的指针的表达式,指向初始值 数组对象的元素,而不是左值。