为什么被调函数内部不能用 sizeof(arr) / size(arr[0]) 计算数组长度?

简介: 该文解答了一个关于C语言的疑问,涉及64位RedPandaDevc++编译器。示例代码展示了不能通过`sizeof(arr)/sizeof(arr[0])`在函数中计算数组长度的问题,因为`arr`在函数中作为指针传递,`sizeof(arr)`返回指针大小(可能是4或8字节),而非数组长度。因此,代码在函数内输出可能为2。而在`main()`函数中,`sizeof(arr)`会计算整个数组大小,正确返回数组长度。文章强调了数组名在不同上下文中的差异以及`sizeof`操作符的使用注意事项。

本文是对该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
}


考点:数组作为函数参数的使用、sizeof 操作符的使用

相关文章
|
负载均衡 Ubuntu 应用服务中间件
|
API 调度
【FreeRTOS】软件定时器的使用
【FreeRTOS】软件定时器的使用
411 0
成功解决A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,co
成功解决A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,co
|
SQL 数据库 开发者
SQL 语言:完整性约束
SQL 语言:完整性约束
389 3
|
11月前
|
移动开发 关系型数据库 MySQL
MySQL中的ROW_NUMBER窗口函数简单了解下
ROW_NUMBER是 MySQL8引入的窗口函数之一,它为查询结果集中的每一行分配一个唯一的顺序号(行号)。ROW_NUMBER在分页、去重、分组内排序等场景中非常有用。
492 4
|
11月前
|
Rust 前端开发 JavaScript
前端性能革命:WebAssembly在高性能计算中的应用探索
【10月更文挑战第26天】随着Web应用功能的日益复杂,传统JavaScript解释执行模式逐渐成为性能瓶颈。WebAssembly(Wasm)应运而生,作为一种二进制代码格式,支持C/C++、Rust等语言编写的代码在浏览器中高效运行。Wasm不仅提升了应用的执行速度,还具备跨平台兼容性和安全性,显著改善了Web应用的响应速度和用户体验。
274 4
|
12月前
|
安全 程序员 C++
双重释放(Double Free)
【10月更文挑战第12天】
498 2
|
前端开发
使用ffmpeg-core的时候报错,解决Uncaught (in promise) ReferenceError: SharedArrayBuffer is not defined
使用ffmpeg-core的时候报错,解决Uncaught (in promise) ReferenceError: SharedArrayBuffer is not defined
|
编译器 C语言
【C语言】字母转换大小写的三种方法
【C语言】字母转换大小写的三种方法
744 0
|
前端开发 API Android开发
26. 【Android教程】网格视图 GridView
26. 【Android教程】网格视图 GridView
290 2