数组名不等于指针 sizeof()函数求数组大小错误问题及解决

 更新时间:2022年11月14日 15:05:00   作者:Z小旋  
这篇文章主要介绍了数组名不等于指针 sizeof()函数求数组大小错误问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

前言 

今天在项目中需要求采样点的数量并且遍历,采样点用数组存储,自定义了一个函数想要用sizeof求其长度,然后遍历,结果失败了,查阅之后发现以下问题:

在main函数中,sizeof是可以正常工作的

#include <stdio.h>

int Number[10];   

int main()
{
	int size = sizeof(Number);
	printf("数组大小为:%d\n",size);
	int len = sizeof(Number)/sizeof(int);
	printf("数组共有%d个数据\n",len);

	return 0;
}

输出:

但是在自定义函数中就不可以了,如下:

#include <stdio.h>

int Number[10]; 

void print_1(int n[])
{
	int size = sizeof(n);
	printf("数组大小为:%d\n",size);
	int len = sizeof(n)/sizeof(int);
	printf("数组共有%d个数据\n",len);
}
  

int main()
{
	
	print_1(Number); 
	
	return 0;
}

那么我们首先要知道sizeof函数的功能:

sizeof是获取数据在内存中所占用的存储空间,以字节为单位来计数。

那么这个时候有的同学就会有问题了,两次传入的都是数组的首地址,为什么主函数中就可以,自定义函数中就不行呢?

得益于谭老爷子的C语言书籍普及量和销量,很多人认为数组名就是指向数组首地址的一个指针,但其实这个说法是错误的!

我们用一个最简单的例子,假设数组名是一个指针,那么:

#include <stdio.h>

int Number[10]; 

int *Number2;
  
int main()
{  
	int a=sizeof(Number);
	int b=sizeof(Number2);
	
	printf("a的大小为:%d \n b的大小为 %d\n",a,b); 
	
	return 0;
}
  • Number是一个指针,Number2也是一个指针,正常情况下 大小都应该为8
  • 但是实际的输出确实 a=40 b=8
  • 也就是说数组名在某些情况下是不等于指针的,只是在一些情况下会退化为指针

首先我们要知道,单纯的数组名,不是指针

数组名是一个标识符,它标识出我们之前申请的一连串内存空间,而且这个空间内的元素类型是相同的——即数组名代表的是一个内存块及这个内存块中的元素类型 。

只是在大多数情况下数组名会“退化”(C标准使用的decay和converted这两个词)为指向第一个元素的指针。

而指针不是一种聚合类的数据结构,它保存着某一种类型的对象的地址(void*除外),也说它指向这个对象。

我们可以通过这个地址访问这个对象。用一个图来解释,其中a代表了整个我们声明的内存块,p仅仅指向了一个char类型的对象

char a[] = {'h' 'e' 'l' 'l' 'o'};
char b[] = {'w' 'o' 'r' 'l' 'd'};

char *p=b;

这是怎么一回事呢?

我们看一下C99标准:

C99 6.3.2.1 Lvalues, arrays, and function designators 中第三段是这样说的:

Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue. If the array object has register storage class, the
behavior is undefined.

这段话的意思是: 数组名只有在

  • sizeof 运算符
  • 取址 & 运算符
  • 字符串常量初始化的数组 Str[]=“abcdef”

这三种情况下不会发生退化(array decay)

其余情况下调用数组名,都会退化成指向数组首地址的指针

再深入的话,就是要了解指针的sizeof

  • 指针是用来记录另一个对象的地址,所以指针的内存大小就等于计算机内部地址总线的宽度。
  • 对一个地址来取大小呢,如果是32位系统的话即为4,如果是64位系统的话为8,所以呢,在函数中sizeof获取的是指针的长度而不是数组的长度
  • 指针变量的sizeof值与指针所指的对象没有任何关系。

结论

也就是说在c语言中,数组名在函数的调用中退化成了一个指针,对函数的参数使用Sizeof,sizeof获取的结果就是指针的大小,而不是数组本身的大小

再了解一下Sizeof的处理时间

sizeof是C语言的一种单目操作符(但有人也不这么以为,认为它是一种特殊的宏),如C语言的其他操作符++、–等一样。它并不是函数

sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定,简单的说其作用就是返回一个对象或者类型所占的内存字节数。

也就是说,Sizeof是一个C语言的操作符,那么他的处理阶段在编译阶段,也就是说你程序没有运行前,sizeof(arr)就被替换成了一个固定的常量,那么对于动态生成的数组大小是不能用sizeof来算出来的。

解决方法

在函数中多加一个参数,表示数组的长度

#include <stdio.h>

int Number[10]; 

void print_1(int n[], int len)
{

	printf("数组大小为:%d\n",len);
	
	printf("数组共有%d个数据\n",len/sizeof(int));

}
  
int main()
{
	
	print_1(Number,sizeof(Number)); 
	
	return 0;
}

以上就是问题的总结。仅为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • OpenCV去除绿幕抠图源码

    OpenCV去除绿幕抠图源码

    这篇文章主要介绍了OpenCV去除绿幕抠图,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • C++类成员函数中的名字查找问题

    C++类成员函数中的名字查找问题

    这篇文章主要介绍了C++类成员函数中的名字查找问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Windows10配置VSCode C++环境(超详细,面向小白以及大佬们)

    Windows10配置VSCode C++环境(超详细,面向小白以及大佬们)

    这篇文章主要介绍了Windows10配置VSCode C++环境(超详细,面向小白以及大佬们),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • C++ Qt QColorDialog使用方法

    C++ Qt QColorDialog使用方法

    本文主要介绍了C++ Qt QColorDialog使用方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C++使用new和delete进行动态内存分配与数组封装

    C++使用new和delete进行动态内存分配与数组封装

    这篇文章主要介绍了C++使用new和delete进行动态内存分配与数组封装,运行期间才能确定所需内存大小,此时应该使用new申请内存,下面我们就进入文章学习具体的操作方法,需要的小伙伴可以参考一下
    2022-03-03
  • C++中try throw catch异常处理的用法示例

    C++中try throw catch异常处理的用法示例

    这篇文章主要给大家介绍了关于C++中try throw catch异常处理的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用C++具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-10-10
  • C语言实现线性动态(单向)链表的示例代码

    C语言实现线性动态(单向)链表的示例代码

    本文主要介绍了C语言实现线性动态(单向)链表的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • C++中二叉堆排序详解

    C++中二叉堆排序详解

    这篇文章主要介绍了C++中二叉堆排序详解,主要介绍了二叉堆排序(递归和非递归实现上沉、下沉算法),需要的朋友可以参考下
    2023-01-01
  • C语言实现获取内存信息并输出的实例

    C语言实现获取内存信息并输出的实例

    这篇文章主要介绍了C语言实现获取内存信息并输出的实例的相关资料,需要的朋友可以参考下
    2017-03-03
  • C/C++连接MySQL数据库详细图文教程

    C/C++连接MySQL数据库详细图文教程

    在实际开发中我们经常需要对数据库进行访问,下面这篇文章主要介绍了C/C++连接MySQL数据库的详细图文教程,文中通过代码以及图文介绍是非常详细,需要的朋友可以参考下
    2024-01-01

最新评论