【C语言学习】数组名的实质-程序员宅基地

技术标签: c语言  C语言学习  

作者:一只大喵咪1201
专栏:《C语言学习》
格言:你只管努力,剩下的交给时间!
图

描述

在需要创建很多相同类型的元素时就要使用到数组,而创建数组就需要给这个数组起个名字,但是这个名字有一定的意义,下面本喵来详细说一下。

一维数组

在内存中的储存

先创建一个一维数组。
代码如下:

#include<stdio.h>

int main()
{
    
	int arr[10] = {
     0,1,2,3,4,5,6,7,8,9 };

	return 0;
}

数组在内存中是这样存储的:
数组存放
每个元素所在的地址如下:

#include<stdio.h>

int main()
{
    
	int arr[10] = {
     0,1,2,3,4,5,6,7,8,9 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
    
		printf("&arr[%d] = %p\n", i, &arr[i]);
	}
	return 0;
}

运行结果:
代码运行结果
可以看到,数组中的每个元素都有一个地址,而且是从低到高,就像是这些元素住在一栋楼里,每个元素占一层,由于创建的是整型数组,每层的大小是4个字节,而数组名就相当于这栋楼,在数组名后加上下标就可以找到对应的元素,就像是门牌号。

一般情况下数组名的实质

#include<stdio.h>

int main()
{
    
	int arr[10] = {
     0,1,2,3,4,5,6,7,8,9 };
	printf("%p\n", &arr[0]);//打印首元素的地址
	printf("%p\n", arr);//打印数组名的地址
	return 0;
}

运行结果
代码运行结果
可以看到,数组名的本质就是数组首元素的地址。

在操作符sizeof下数组名的实质

sizeof操作符的作用是求出数据所占内存空间的大小。当数组名遇到了sizeof时就不是代表数组首元素地址了,而是代表的整个数组,就像上诉所说的整栋楼。

#include<stdio.h>

int main()
{
    
	int arr[10] = {
     0,1,2,3,4,5,6,7,8,9 };
	int sz = sizeof(arr);//求数组大小
	printf("sizeof(arr) = %d\n", sz);
	return 0;
}

运行结果:
代码运行结果
可以看到结果是40,由于创建的是整型数组,里面又10个元素,每个元素的大小是4个字节,所以得出的结果是40。
此时数组名代表的就是整个数组。

在操作符&下数组名的实质

&是取地址操作符,就是得到所创建变量在内存中的地址。
当数组名遇到&时的实质会是什么呢?

#include<stdio.h>

int main()
{
    
	int arr[10] = {
     0,1,2,3,4,5,6,7,8,9 };
	printf("%p\n", &arr[0]);//打印首元素地址
	printf("%p\n", &arr[0] + 1);//打印首元素地址加1
	printf("\n");
	printf("%p\n", &arr);//打印数组名取地址
	printf("%p\n", &arr + 1);//打印数组名取地址加1
	return 0;
}

运行结果:
代码运行结果
首元素地址加1的结果就是在首元素地址的基础上加了4个字节。
数组名取地址加1的结果是在首元素地址的基础上加了40个字节。
虽然首元素地址是数组名地址的表现相同,但是实质不同。
首元素取地址的打印结果是首元素地址,但是数组名取地址代表的是整个数组的地址,当加1后直接加了40个字节,也就是加了整数组元素所占的内存。
此时数组名代表的就是整个数组。

二维数组

在内存中的储存

先创建一个二维数组。
代码如下:

#include<stdio.h>

int main()
{
    
	int arr[3][4] = {
     {
    1,2,3},{
    3,4,5,6},{
    1,2} };//创建二维数组,三行四列,空白部分自动用0填充
	return 0;
}

二维数组在内存中是这样储存的:
储存
每个元素所在的地址如下:

#include<stdio.h>

int main()
{
    
	int arr[3][4] = {
     {
    1,2,3},{
    3,4,5,6},{
    1,2} };//创建二维数组,三行四列,空白部分自动用0填充
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)//外循环控制行
	{
    
		for (j = 0; j < 4; j++)//内循环控制列
			printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
		printf("\n");
	}
	return 0;
}

运行结果:
代码运行结果
可以看到,数组中的每个元素都有一个地址,而且是从低到高,同样可以理解为这些元素住在一栋楼里,每个元素占一成,大小是四个字节,在数组名后加上下标就可以找到具体的某个元素。
注意
二维数组可以看出是一维数组,一维数组的成员是arr[0],arr[1],arr[2],即数组的每一行看成是一个成员,就像在楼里的每4个元素看成一户,一共有3户,就是12个元素。

一般情况下数组名的实质

#include<stdio.h>

int main()
{
    
	int arr[3][4] = {
     {
    1,2,3},{
    3,4,5,6},{
    1,2} };//创建二维数组,三行四列,空白部分自动用0填充
	printf("%p\n", &arr[0][0]);//打印首元素地址
	printf("%p\n", &arr[0][0] + 1);//打印首元素地址加1
	printf("\n");
	printf("%p\n", arr);//打印数组名取地址
	printf("%p\n", arr + 1);//打印数组名取地址加1
	return 0;
}

运行结果:
代码运行结果
数组元素首地址加1后地址多了4个字节。
数组名加1后地址多了16个字节,因为一行元素是4个,所占空间大小是16个字节。
可以看到,二维数组名的本质是首行元素的地址,但是表现出来的值与首元素地址相同。

在操作符sizeof下数组名的实质

sizeof操作符的作用上面已经介绍过。当二维数组名遇上sizeof也是代表的整个数组,二维数组的行名arr[i]遇上sizeof代表的这一行。

#include<stdio.h>

int main()
{
    
	int arr[3][4] = {
     {
    1,2,3},{
    3,4,5,6},{
    1,2} };//创建二维数组,三行四列,空白部分自动用0填充
	int sz1 = sizeof(arr);//求整个数组的大小
	int sz2 = sizeof(arr[0]);//求第一行的大小
	printf("sizeof(arr) = %d\n", sz1);
	printf("sizeof(arr[0]) = %d\n", sz2);
	return 0;
}

运行结果:
代码运行结果

  1. 可以看到,当是arr时,结果是48,由于创建的整型数组有12个元素,每个元素大小是4个字节,所以整个数组的大小是48个字节。
  2. 当是arr[0]时,结果是16,由于一行有四个元素,所以是16个字节。
    此时数组名代表的是整个数组,数组的行名代表的是这一行。

二维数组行数和列数的求法:

#include<stdio.h>

int main()
{
    
	int arr[][4] = {
     1,2,3,4,5,6,7,8,9,10,11,12 };//创建二维数组时,行可以省略,列不能省略
	int row = sizeof(arr) / sizeof(arr[0]);//行数就等于整个数组的大小除以第一行的大小
	int col = sizeof(arr[0]) / sizeof(arr[0][0]);//列数就等于第一行的大小除以首元素的大小
	printf("是一个%d行%d列的二维数组\n", row, col);
	return 0;
}

运行结果:
代码运行结果

在操作符&下数组名的实质

&操作符的作用在上面已经介绍过。
当数组名遇到&时的实质又是什么呢?

#include<stdio.h>

int main()
{
    
	int arr[3][4] = {
     {
    1,2,3},{
    3,4,5,6},{
    1,2} };//创建二维数组,三行四列,空白部分自动用0填充
	printf("&arr[0][0]   = %p\n", &arr[0][0]);
	printf("&arr[0][0]+1 = %p\n", &arr[0][0] + 1);//打印首地址元素加1
	printf("\n");
	printf("&arr   = %p\n", &arr);//打印数组名取地址
	printf("&arr+1 = %p\n", &arr + 1);//打印数组名取地址加1
	printf("\n");
	printf("&arr[0]   = %p\n", &arr[0]);//打印数组首行名取地址
	printf("&arr[0]+1 = %p\n", &arr[0] + 1);//打印数组首行名取地址加1
	return 0;
}

运行结果:
代码运行结果
首元素地址加1后多出了4个字节。
数组名取地址加1后多出了48个字节,是所有元素所占空间的大小。
数组首行名取地址加1后多除了16个字节,是首行元素所占空间的大小。
虽然首元素地址和数组名取地址已经数组首行元素取地址的表现相同,但是实质不同。
首元素取地址打印的结果就是首元素的地址,但是数组名取大致代表的整个数组,数组某行元素取地址代表的是这一行的地址。

总结

一般情况下,一维数组的数组名的本质就是首元素的地址,二维数组的数组名是首行元素的地址,只有在两种特殊情况,也就是遇到sizeof操作符和&操作符时,一维数组和二维数组的数组名代表的是整个数组。
二维数组也可以看作是一维数组,这时每一行就是一维数组的一个元素。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_63726869/article/details/124433269

智能推荐

Win10下go+grpc+protobuf环境搭建_protoc-gen-go-grpc.exe-程序员宅基地

文章浏览阅读1.4k次。1、_protoc-gen-go-grpc.exe

TypeError: data type not understood_typeerror: data type 'uint-8' not understood-程序员宅基地

文章浏览阅读1.2w次。python的二维数据表示要用二层括号来进行表示。如:产生一个2×3的全0矩阵,若是zeros(2,3)这种写法就会出现 TypeError: data type not understood 这种错误; 正确的写法是 zeros((2,3))..._typeerror: data type 'uint-8' not understood

机器学习/数据挖掘之中国大牛_机器学习数据空间 知乎-程序员宅基地

文章浏览阅读2.7k次,点赞2次,收藏3次。推荐几个机器学习和数据挖掘领域相关的中国大牛:李航:http://research.microsoft.com/en-us/people/hangli/,是MSRA Web Search and Mining Group高级研究员和主管,主要研究领域是信息检索,自然语言处理和统计学习。近年来,主要与人合作使用机器学习方法对信息检索中排序,相关性等问题的研究。曾在人大听过一场他的讲座,对实际应用_机器学习数据空间 知乎

Source Insight4.0 不显示文件列表/工程文件目录_source insight文件列表不显示-程序员宅基地

文章浏览阅读5.2k次,点赞6次,收藏10次。软件设置里面勾选上Project File List就行了。_source insight文件列表不显示

SS928官方vo例子适配mipi屏-程序员宅基地

文章浏览阅读1k次。最近新购一款SS928的开发板,但其外部只提供了HDMI显示接口,官方未适配MIPI屏,考虑到调试的时候每次找HDMI显示器不方便,就自己画了个板子匹配了一款mipi的显示屏,屏幕为:8.0 inch IPS MIPI 800x1280 AML08021016-31D Amelin Electronic Technology。一般由厂家提供,主要通过mipi命令模式向屏幕写入寄存器配置信息,我这个屏幕参数组成为{地址,长度,数据1,…01 EB-SS928-DC-393型开发板用户快速入门.pdf。_ss928

IDEA maven命令报错:打包程序包com.sun.istack.internal不存在_com.sun.istack.internal.notnull-程序员宅基地

文章浏览阅读1.1w次,点赞10次,收藏6次。错误信息:错误原因:因使用到 @NotNull注解导致,引入相应的包即可解决方案:pom文件中加入如下配置&amp;amp;amp;amp;amp;lt;build&amp;amp;amp;amp;amp;gt; &amp;amp;amp;amp;amp;lt;plugins&amp;amp;amp;amp;amp;gt; &amp;amp;amp;amp;amp;lt;plugin&amp;amp;_com.sun.istack.internal.notnull

随便推点

STM32+AIR800关于温湿度采集上传阿里云以及进行云端下发指令简单的控制_基于stm32温湿度上传云平台-程序员宅基地

文章浏览阅读8.7k次,点赞6次,收藏105次。一、主要功能实现:1、STM32采集温湿度上传至阿里云,进行云端显示2、云端下发指令控制STM32的LED亮灭(直接控制STM32(A)的LED亮灭,以及设置定时时间自动打开和关闭LED)3、云端下发指令通过NRF24L01间接控制第二个STM32(B)的LED亮灭二、 各模块功能划分:1、阿里云物联网云平台:(1)进行云端显示温湿度,给云下设备下达指令2、AIR800:(1)成功..._基于stm32温湿度上传云平台

QT c++ 中使用PostMessage/SendMessage_qt sendmessage-程序员宅基地

文章浏览阅读2.6w次,点赞3次,收藏39次。 PostMessage是Windows API(应用程序接口) 中的一个常用函数,用于将一条消息放入到消息队列中。并且不会等待响应的线程处理消息,而是直接返回。(简单的理解就是异步)。而SendMessage作用一样,但是会等待结果返回(同步)我们先来看PostMessage函数的原型:BOOL WINAPI PostMessage(HWND hWnd, UINT Msg, W..._qt sendmessage

初始对准及组合导航技术_双位置对准-程序员宅基地

文章浏览阅读9.5k次,点赞22次,收藏129次。一、对准是确定坐标系的过程1、初始对准比如说:初始对准就是确定的过程,通过重力加速度和地球自转角速度,其中,天向通过重力加速度确定,水平面的东北向通过地球自转角速度的分量确定。2、坐标系对准比如说,地面车辆中,IMU任意放置,如何确定;可以看出,对准就是确定坐标系的过程。3、矢量定姿<1>双矢量定姿矢量和不共线,因此,、和不共面,其三个矢量构成的矩阵可逆。由于上述矢量构建的姿态矩阵未必满足正交化要求,因此,预先对解算的矢量进行正交及单位化处理。即上述._双位置对准

QT——手动编译qt源代码过程_qt怎么编译-程序员宅基地

文章浏览阅读3.5k次。1.生成解决方案终端进入需要手动编译的项目所在的目录在该目录下执行qmake -project命令,注意qmake前面的路径是qmake的安装路径:/Qt5.11.3/5.11.3/gcc_64/bin/qmake -project该文件夹下会生成.pro文件注意:需要在该文件中添加项目执行过程中需要的模块,笔者的文件中添加了 QT += widgets2.生成Makefile文件..._qt怎么编译

VUE——MVVM框架理解_vue框架是mvvm-程序员宅基地

文章浏览阅读315次。MVVM工作原理MVVM框架理解MVVM的实现原理响应式:模板解析:如何将模板渲染为html小白一枚,正好最近Vue越来越火热,Github上的Star数已经超过了React。而其背后蕴含的MVVM框架思想也一直跟React的组件化开发思想并驾齐驱,在这里也是本着兼收并蓄的思想,多了解一种开发模式。因此通过一些学习资料,写一些自己对MVVM开发思想的理解。废话不多说,咱们进入正题。MVVM框..._vue框架是mvvm

内存修改器对游戏的危害_内存挂容易被检测吗-程序员宅基地

文章浏览阅读3.9k次,点赞4次,收藏10次。内存修改器是游戏外挂里面的一个大类,通过修改器可实现很多魔幻且具有很大破坏性的功能。 下面几张图是使用修改器实现的游戏破解效果。 内存修改器实现的透视功能 ..._内存挂容易被检测吗

推荐文章

热门文章

相关标签