本文是对该C语言小困惑的一个解答。
本文测试采用的编译器为64位的 RedPandaDevc++编译器。
我们给出如下测试代码:
int Test(int arr[]){ return sizeof(arr)/sizeof(arr[0]); } int main(){ int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int ret = Test(arr); printf("%d",ret); }
提出这个困惑的朋友们都知道,这段代码是不可能实现“计算数组长度”这个功能的。
那么它的输出结果可能是多少呢?
在64位编译器中,显示的结果为 2
解答:
∵ 数组名作为函数实参传递时,传递的实际是其首元素的地址。接收的一方,接收的实际是指针。
上述代码中, int ret = Test(arr); 这当中的arr是数组的首元素地址,即&arr[0]
int Test(int arr[]),int arr[]等价于int* arr,用作接收的形参实际是指针。
∴ 在函数中,sizeof(arr),arr虽然和数组名长得一样,但其实并不是数组名,而是指针变量(相当于 int* p,sizeof(p))
∴ 指针变量的长度是4字节或8字节,sizeof(指针变量)自然就输出4或8
//测试一下指针变量的长度 int main(){ int a; int* p = &a; printf("%zu",sizeof(p)); return 0; }
所以同理,在被调函数内部,由于arr也是指针,sizeof(arr)并不会输出数组的长度,而是指针变量的长度,也会输出4或者8.
有些同学可能会纠结于,数组名不就代表首元素的地址吗?是的,数组名在大部分情况下代表数组首元素地址(例外情况下面说),但和本题是两码事。
虽然首元素的地址和数组的地址是同一个,但是不影响一个是指针一个是数组名。记住被调函数中没有整个数组,只有一个指针即可。
回到 sizeof(arr) / size(arr[0]) 这一表达式。sizeof(arr)值为8(或4),arr[0]为普通的int类型变量,sizeof(arr[0])的值和sizeof(int)的值相等,都是4 (int类型的长度也是有可能为8的,而我的编译器是4)。因而整个表达式的值是 8/4 ,输出的结果自然是2了。
但在main函数中,sizeof(arr)是会计算整个数组所占的内存空间大小。因为在sizeof中,arr并不表示数组首元素的地址,而表示整个数组。这就是数组名不表示数组首元素地址的例外情况。
可以作为结论记住:sizeof(数组名)与&数组名,正是数组名不表示数组首元素地址的例外情况。
(&数组名,取的是整个数组的地址。上述代码中的&arr+1 ,地址增加了40(个存储单元),而arr+1 和 &arr[0]+1 相等,地址增加了 4 )
int main(){ int arr[10] = {1,2,3,4,5,6,7,8,9,10}; //int ret = Test(arr); printf("%zu",sizeof(arr)); //计算出arr数组的总空间为40 }
int main(){ int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int ret = sizeof(arr)/sizeof(arr[0]); printf("%d",ret); //计算出该数组的长度为10 }