为什么被调函数内部不能用 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 操作符的使用

相关文章
|
C++ 索引
Windows10下VS2015下载安装详解【附“安装包丢失或损坏“ 错误解决方法】
Windows10下VS2015下载安装详解【附“安装包丢失或损坏“ 错误解决方法】
11669 0
Windows10下VS2015下载安装详解【附“安装包丢失或损坏“ 错误解决方法】
|
Linux
linux yum 安装rar和unrar
linux yum 安装rar和unrar
1368 0
|
缓存
HTTP 请求头Cache-Control 详解
HTTP 请求头Cache-Control 详解
931 0
|
数据库 UED Python
1、基于python多进程+pyqt5开发流畅界面程序
使用python+pyqt5开发界面程序,利用多进程分离界面和任务执行功能,达到界面流畅不卡顿的要求。 本文程序示例:https://github.com/AlvinsFish/UiExample
2924 0
1、基于python多进程+pyqt5开发流畅界面程序
|
存储 JSON NoSQL
Node.js使用数据库LevelDB:超高性能kv存储引擎
Node.js被设计用来做快速高效的网络I/O。它的事件驱动流使其成为一种智能代理的理想选择,通常作为后端系统和前端之间的粘合剂。Node的设计初衷就是为了实现这一目的,但与此同时,它已成功用于构建传统的Web应用程序:一个HTTP服务器,提供为HTML页面或JSON消息响应,并使用数据库存储数据。
1132 0
Node.js使用数据库LevelDB:超高性能kv存储引擎
|
数据库连接
DbVisualizer数据库连接工具默认查询结果只显示100条解决方法,dbvis如何展示更多行,如何显示全部数据
DbVisualizer数据库连接工具默认查询结果只显示100条解决方法,dbvis如何展示更多行,如何显示全部数据
1873 0
DbVisualizer数据库连接工具默认查询结果只显示100条解决方法,dbvis如何展示更多行,如何显示全部数据
|
存储 编译器 C语言
【C语言】16 位的值,通过几种不同的方式将其拆分为高 8 位和低 8 位
在实际应用中,通常使用方法 1(位移和位掩码)是最常见的选择,因为它简单、直观,并且不依赖于特定的硬件或编译器特性。方法 3(联合体)适用于需要处理复杂数据结构或需要同时访问多个字段的情况。方法 4(内联函数或宏)适用于需要提高代码重用性和可读性的场景。方法 2(指针和强制类型转换)虽然有效,但不推荐,因为它可能会引入平台依赖性和对齐问题。
757 2
|
安全 程序员 C++
双重释放(Double Free)
【10月更文挑战第12天】
763 2
|
存储 算法 C语言
c语言实现HashTable
本文介绍了如何在C语言中实现哈希表(HashTable),包括定义节点结构、自定义哈希函数、创建节点、插入节点、搜索节点和删除节点的完整过程。
448 0
c语言实现HashTable
|
测试技术 开发者 C++
【Qt 职业生涯规划】Qt 开发者的多元宇宙:从桌面到嵌入式,从2D到3D,你适合哪条路?
【Qt 职业生涯规划】Qt 开发者的多元宇宙:从桌面到嵌入式,从2D到3D,你适合哪条路?
854 1