江牧律师
首页
往期整理
  •   历史归档
  •   文章分类
  •   文章标签
关于我
江牧
文章
10
分类
2
标签
6
首页
往期整理
历史归档
文章分类
文章标签
关于我
技术学习
C/C++不能在子函数中求主函数中的数组长度
发布于: 2024-8-28
最后更新: 2024-10-9
次查看
C语言
知识点
type
status
date
slug
summary
tags
category
icon
password
😀
在子函数形参中传递数组名时只会传递数组的首地址,而不是整个数组。

1.子函数形参中传递数组的本质

先看一段代码:
 
我们都知道,参数的传递是把实参的副本传递给形参,但数组较例外。 在子函数形参中传递数组名时只会传递数组的首地址,而不是整个数组(毕竟假如数组有1万个元素,全部拷贝一份给形参实在是过于浪费内存空间),函数在后面需要用到数组元素时再根据首地址和下标去找。
当实参将arr数组首元素地址传递到函数时,形参用指针进行接收,想使用:sizeof(arr)/sizeof(arr[0]) 来求数组大小是行不通的,因为此时的sizeof(arr)并不是整个数组的大小了,表示的是求这个arr指针的字节大小。因此sizeof(arr)/sizeof(arr[0])这个表达式在函数内部会等价sizeof(int*)/sizeof(int),它计算的是指针大小与单个int元素大小的比值,而不是数组的元素数量。
综上,想要规避掉这个错误,我们一般都是在主函数/调用的地方中求出数组的具体长度,然后将长度作为参数传递给子函数。
 
那么这个时候有的同学就会问了,两次传入的都是数组的首地址,为什么主函数中就可以,自定义函数中就不行呢?
 

2.数组名不完全等同于指针

再看一段代码:
也就是说数组名在某些情况下是不等于指针的,只是在一些情况下会退化为指针。
 
首先我们要知道,单纯的数组名,不是指针。
 
数组名是一个标识符,它标识出我们之前申请的一连串内存空间,而且这个空间内的元素类型是相同的——即数组名代表的是一个内存块及这个内存块中的元素类型 。
 
只是在大多数情况下数组名会“退化”(C标准使用的decay和converted这两个词)为指向第一个元素的指针。 而指针不是一种聚合类的数据结构,它保存着某一种类型的对象的地址(void*除外),也说它指向这个对象。我们可以通过这个地址访问这个对象。用一个图来解释,其中a代表了整个我们声明的内存块,p仅仅指向了一个char类型的对象。
notion image
 
于是我们翻阅C99标准可知:
数组名只有在
  1. sizeof运算符
    1. 取址&运算符
        • &数组名,这里的数组名表示整个数组,取出的是整个数组的地址
          • int arr[]={1,2,3,4,5};
            &arr+1
            arr+1=&arr[0]+1
            &arr是指向整个数组的指针,因此,如果我们将&arr移动1个位置,它将移动一整个数组的地址,指向下一个包含5个元素的块。
            arr是指向数组第一个元素的指针。因此,如果我们将arr移动1个位置,它将指向第二个元素。
            如果数组基地址为00D5F940,则&arr+1将为00D5F940+(5*4),即00D5F954
            如果数组基地址是00D5F940 ,则arr+1将是00D5F940+4,即00D5F944
            notion image
    1. 字符串常量初始化的数组Str[]=“abcdef”
    这三种情况下不会发生退化(array decay) 其余情况下调用数组名,都会退化成指向数组首地址的指针
     
    而指针是用来记录另一个对象的地址,所以指针的内存大小就等于计算机内部地址总线的宽度。
    对一个地址来取大小呢,如果是32位系统的话即为4,如果是64位系统的话为8,所以呢,在函数中sizeof获取的是指针的长度而不是数组的长度
    指针变量的sizeof值与指针所指的对象没有任何关系。
    • 结论:也就是说在c语言中,数组名在函数的调用中退化成了一个指针,对函数的参数使用sizeof,sizeof获取的结果就是指针的大小,而不是数组本身的大小。
     

    3.练习

    写一个函数,实现一个整形有序数组的二分查找

    🤗 总结归纳

    数组名在函数的调用中退化成了一个指针,传递时只会传递数组的首地址,对函数的参数使用sizeof,sizeof获取的结果就是指针的大小,而不是数组本身的大小。

    📎 参考文章

    • https://blog.csdn.net/as480133937/article/details/123512497
    • https://blog.csdn.net/m0_74088266/article/details/137431046
    • https://www.cnblogs.com/ezhar/p/13901733.html
    • 作者:江牧
    • 链接:https://lawyerjiang.top/article/key/c/3
    • 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
    相关文章
    document.write()、textContent、innerText 与innerHTML的区别
    计算输入的数字在二进制下包含1的个数
    解引用“指向空间已被释放的指针”,会得到怎样的值?
    序列中删除指定数字
    C语言中将数字0~9与对应字符相互转换
    快速理解C语言指针和数组的关系
    C语言中将数字0~9与对应字符相互转换快速理解C语言指针和数组的关系
    Loading...
    目录
    0%
    1.子函数形参中传递数组的本质2.数组名不完全等同于指针3.练习🤗 总结归纳📎 参考文章
    江牧
    江牧
    无限进步!
    文章
    10
    分类
    2
    标签
    6
    最新发布
    记一次个人服务器的搭建过程
    记一次个人服务器的搭建过程
    2025-4-28
    document.write()、textContent、innerText 与innerHTML的区别
    document.write()、textContent、innerText 与innerHTML的区别
    2024-10-9
    起点
    起点
    2024-10-9
    解引用“指向空间已被释放的指针”,会得到怎样的值?
    解引用“指向空间已被释放的指针”,会得到怎样的值?
    2024-10-9
    C语言中将数字0~9与对应字符相互转换
    C语言中将数字0~9与对应字符相互转换
    2024-10-9
    C/C++不能在子函数中求主函数中的数组长度
    C/C++不能在子函数中求主函数中的数组长度
    2024-10-9
    公告
    -- 本网站正处于大规模装修建设中 --
    目录
    0%
    1.子函数形参中传递数组的本质2.数组名不完全等同于指针3.练习🤗 总结归纳📎 参考文章
    2022-2025 江牧.

    江牧律师 | 无限进步!

    Powered by NotionNext 4.7.4.