数组名不等于指针 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;
}

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

相关文章

  • C语言实现学生成绩等级划分的方法实例

    C语言实现学生成绩等级划分的方法实例

    这篇文章主要给大家介绍了关于C语言实现学生成绩等级划分的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • C语言结构体,枚举,联合体详解

    C语言结构体,枚举,联合体详解

    下面小编就为大家带来一篇全面了解C语言结构体,枚举,联合体。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-09-09
  • C++算法学习之回溯法的应用

    C++算法学习之回溯法的应用

    这篇文章介绍了C++算法中回溯法的一些应用,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • C++图文并茂分析讲解模板

    C++图文并茂分析讲解模板

    C++语言的模板技术包括函数模板和类模板,模板技术是一种代码重用技术,函数和类是C++语言中两种主要的重用代码形式,这篇文章主要介绍了C++函数模板和类模板,需要的朋友可以参考下
    2022-09-09
  • C++ 实现读写锁的代码详解

    C++ 实现读写锁的代码详解

    C++读写锁是一种多线程同步机制,它允许多个线程同时读取共享数据,但只允许一个线程写入共享数据,这种锁可以提高程序的并发性和性能,本文给大家介绍了C++ 实现读写锁的代码,需要的朋友可以参考下
    2023-10-10
  • C++如何删除map容器中指定值的元素详解

    C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-06-06
  • C++17新特性个人总结

    C++17新特性个人总结

    这篇文章主要介绍了C++17新特性个人总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • C++ STL 中的数值算法示例讲解

    C++ STL 中的数值算法示例讲解

    本片文章讲解了C++STL 中的数值算法,包含iota、accumulate、adjacent_difference、inner_product、partial_sum这些方法的使用,感兴趣的朋友来看看吧<BR>
    2022-04-04
  • C语言字符串函数入门

    C语言字符串函数入门

    这篇文章主要为大家介绍了C语言字符串函数,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • 关于VS2022不能使用<bits/stdc++.h>的解决方案(万能头文件)

    关于VS2022不能使用<bits/stdc++.h>的解决方案(万能头文件)

    #include<bits/stdc++.h>包含了目前 C++ 所包含的所有头文件,又称万能头文件,那么如何在VS2022中使用万能头呢?下面小编给大家代理了关于VS2022不能使用<bits/stdc++.h>的解决方案(万能头文件),感兴趣的朋友一起看看吧
    2022-03-03

最新评论