sizeof数组澄清
我正在C中学习明天的最后一个,并对sizeof运算符有疑问。
假设int
的大小是32
位,指针是64
位。
如果有function:
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
可能有多大的线索。
这在C语法中是不对称的。 在C中,不可能将数组传递给函数,因此当您在其中一个参数的函数声明中使用数组语法时,编译器会将其作为指针读取。
在大多数情况下,当您在表达式中使用数组时,数组会隐式转换为指向其第一个元素的指针,这正是您调用函数时所发生的情况。 在以下代码中:
int bar[] = {1,2,3,4}; foo(bar);
数组被转换为指向第一个元素的指针,这就是函数接收的内容。
然而,这种隐含转换规则并不总是适用。 正如您发现的那样, sizeof
运算符在数组上工作,甚至&
(address-of)运算符也适用于原始数组(即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 */
(实际上编译器可以发出警告,但代码完全合法C,如果编译器遵循标准则必须接受)
如果你认为这个关于数组的规则在函数参数中是奇怪的那么我同意,但这就是C语言的定义方式。
因为zip是一个数组 ,编译器在编译时知道它的大小。 它只是对两个不同的东西使用相同的符号的情况,这在C中很常见。
int foo (int zap[])
完全等同于
int foo (int *zap)
编译器不知道zap有多大(所以它留给了程序员找到的任务)。
zip
是一个6 * sizeof(int)
的内存块,所以它的大小为24(在你的架构上)。 zap
(它也可以在函数声明中写成int *zap
)但是可以指向任何内存地址,并且编译器无法知道从这个(甚至包含这个)地址开始分配了多少空间。
zip
的大小在编译时是已知的,而zap
的大小则不是。 这就是为什么你得到sizeof(zap)
上的指针sizeof(zap)
和sizeof(zip)
上数组的大小。
在某些情况下,arrays会衰减到指针。 函数调用就是其中之一。
因为它已经被6个elemens静态初始化。