我正在C学习明天的最后一个,并对sizeof运算符有疑问。
假设int
的大小为32
位,指针为64
位。
如果有功能:
int
foo (int zap[])
{
int a = sizeof(zap);
return a;
}
因为zap
是指针,foo
将返回8
,因为这是存储此特定指针所需的字节数。但是,使用以下代码:
int zip[] = { 0, 1, 2, 3, 4, 5 };
int i = sizeof(zip);
i
将为6 * sizeof(int)
= 6 * 4
= 24
为什么sizeof(zip)
返回的元素数量乘以每个元素的大小,而sizeof(zap)
返回指针的大小?是zap
的大小未指定,zip
不是吗?编译器知道 zip
是6
个元素,但没有关于zap
可能有多大的线索。
答案 0 :(得分:8)
这是C语法中的一种不对称。在C中,不可能将数组传递给函数,因此当您在其中一个参数的函数声明中使用数组语法时,编译器会将其作为指针读取。
在大多数情况下,在表达式中使用数组时,数组会隐式转换为指向其第一个元素的指针,这正是调用函数时所发生的情况。在以下代码中:
int bar[] = {1,2,3,4};
foo(bar);
数组被转换为指向第一个元素的指针,这就是函数接收的内容。
但始终不会应用此隐含转换规则。例如,您发现sizeof
运算符适用于数组,甚至&
(地址)运算符也适用于原始数组(即sizeof(*&bar) == 4*sizeof(int)
)。
C中的函数不能将数组作为参数接收,它只能接收指向第一个元素的指针,或者指向数组的指针......或者必须将数组包装在结构中。
即使你在函数声明中的括号之间放了一个数字......
void foo(int x[4])
{
...
}
编译器完全忽略了该编号...编译器的声明完全等同于
void foo(int *x)
{
...
}
,例如,即使调用它传递一个不同大小的数组也不会触发任何错误......
int tooshort[] = {1,2,3};
foo(tooshort); /* Legal, even if probably wrong */
(实际上编译器 MAY 发出警告,但代码完全合法C,如果编译器遵循标准则必须接受)
如果你认为在函数参数中关于数组的这个规则很奇怪,那么我同意,但这就是C语言的定义方式。
答案 1 :(得分:2)
因为zip是数组,并且编译器知道编译时的大小。它只是对两种不同的东西使用相同的符号的情况,这在C中很常见。
int
foo (int zap[])
完全等同于
int
foo (int *zap)
编译器不知道zap有多大(所以它留给了找程序员的任务)。
答案 2 :(得分:2)
zip
是6 * sizeof(int)
的内存块,因此它的大小为24(在您的架构上)。
zap
(它也可以在函数声明中写成int *zap
)但是可以指向任何内存地址,编译器无法知道从这个(或者甚至包含这个)地址开始有多少空间已被分配。
答案 3 :(得分:0)
zip
的大小在编译时是已知的,而zap
的大小则不是。这就是为什么你得到sizeof(zap)
上指针的大小和sizeof(zip)
上数组的大小。
答案 4 :(得分:0)
在某些情况下,阵列会衰减到指针。函数调用就是其中之一。
答案 5 :(得分:-1)
因为它已经被6个elemens静态初始化。