[学习小结]数组名与数组首元素地址解析

C语言中数组首地址和数组第一个元素的地址有什么区别 C语言中数组首地址和数组第一个元素的地址关系如下:1、它们的地址值是相等的。2、第1个元素的地址如果是p,则p+1就是第2个元素的地址。3、数组的首地址如果是p,则p+1就跳过这个数组而指向这个数组最后一个元素最后一个字节的下一字节。 阅读详情
 

2012.04.12



学C++的日子里经常被莫名其妙的问题(没意义但是很纠结的问题)给缠住,然后想了半天,大概是处于这么一个状态:知道怎么用,但是却不知道为什么是这样,而且还带有一点疑问。

今天被 变量名 这个问题给缠住了。因为我有个概念,CPU只认识地址,那么声明个变量到底是怎么回事,这个变量不是地址啊。


然后得出了这个结论。


编译器都帮我们弄好了,机器码内是没有变量符号地址的,只是为了帮助我们阅读而已。全局变量之类的,应该都在运行开始的时候就分配好了,而在函数体内的局部变量,即声明个变量,都是借由编译器改变esp的地址来分配堆栈段空间,而我们的变量的地址,则由编译器编译时候的符号表来替代成地址了。


一个变量,依我理解,在符号表内至少有2个属性,引用的内存地址,类型

int a=0;

符号表就会有a这个符号,同时会有分配好的内存的地址。这个内存地址每次运行不一定是相同的,受到进入函数体时候ebp的影响。则定义一个变量,只是把esp移相应字节数。而访问这个a变量,则替换成引用符号表内的地址的内存,是根据ebp偏移相应字节来访问的。


即高级语言的a=1的赋值语句,将符号表中a地址解引用访问到那个栈内存块,然后赋值。



而上述讨论的指针和数组名,似乎也能这么理解。


数组名只是存在于编译器编译过程中的一个符号而已,这个符号记录的信息,肯定有类型,类似于int[5]之类的,然后就是数组名所指向的地址了。所以数组名是不分配空间的。


对数组元素的访问,可以这样的分析。


int a[5];

int b=a[0];


这种访问方式,则编译后分配数组a空间的时候esp移动了4*5字节,同时符号表内a对应着起始地址。访问时a的符号表直接替换a,用地址+0 的偏移访问元素。也可以理解为什么用a的符号能得到数组的长度。


char *szA="hello";

int c=szA[2];


这种方式,则首先会为szA分配空间,即符号表存在着szA的符号,同时有着szA引用的内存,szA引用的内存存放着字符串常量"hello"的地址。

访问时,szA被*pszA替代,pszA就是符号表记录的szA引用的内存地址,同时用该内存地址的值+偏移量来访问字符串的值。


所以,个人理解是在编译过程中,定义一个变量的时候,会增加一个符号表的内容(变量名,数组名,函数名等),然后在堆栈区分配空间,记录它引用的内存的地址(变量),或者代表的地址(数组名函数名等),定义一个变量最终是转化为机器认得的地址,接下来所有引用到这个变量的东西均由符号表内的内容替换成地址。



一段简单的代码

int _tmain(int argc, _TCHAR* argv[])
{
	int a;
	int *b=&a;
	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
00411A00  push        ebp               //保存进入main函数前的ebp堆栈段基址
00411A01  mov         ebp,esp 		//更新ebp基址,用于寻址main函数下的局部变量
00411A03  sub         esp,0CCh 		//减去相应字节数来增加局部变量
00411A09  push        ebx  
00411A0A  push        esi  
00411A0B  push        edi  		//保存寄存器数值
00411C9C  lea         edi,[ebp+FFFFFF28h] 
00411CA2  mov         ecx,36h 
00411CA7  mov         eax,0CCCCCCCCh 
00411CAC  rep stos    dword ptr [edi] 
	int a;
	int *b=&a;
00411CAE  lea         eax,[ebp-8] 	//最终a的符号被[ebp-8]替代来访问引用的内存
00411CB1  mov         dword ptr [ebp-14h],eax 
	return 0;
00411CB4  xor         eax,eax 
}









在课堂上老师经常把这两者等价,可是是否两者是一样的呢?

 

我们来看一个例子:

int a[5];

cout<<sizeof(a);

int* p=a;

cout<<sizeof(a);

 

若两者是等价的,那么两者的输出应该是一样的,可事实是第一个输出了数组的总长度sizeof(int)*5,而第二个输出了32位机器上的地址长度,也就是记录一个地址需要4字节。由此可见数组名绝对不是简简单单的一个数组首地址而已。

 

由此我们可以推论,实际上还存在着某种特殊的数据结构,似乎与int float等内置基本类型相同的类型。按命名法则,可以推断a的类型是int[5]!

存在int[5]这种类型么?

请在编译器中输入以下代码:

    int a[5];
    int *p=0;
    a=p;

这说明了两个问题:

1.存在int[5]类型,详情请见编译器错误提示。

2.a是一个int[5]类型,而且这种类型是个常量,即不可修改。

所以说,C++中是存在这个类型的,我们也可以写如下的代码:

int a[5];

int (*p)[5];

p=&a;

 

上述代码是什么意思呢?我们首先定义了一个数组,然后声明了一个p指针,这个指针是指向了int[5]类型的,即a,故需要给a取地址,这也侧面说明了为什么声明一个指针需要说明数组的维数,因为int[5]和int[6]的类型是不同的!

而又由于int[5]可以隐式转换为int*,故上述的p指针其实也是一个int**,但其实是上述定义的int(*)[5],为什么呢,读者可以再次对p进行sizeof(*p)操作,可发现依旧能得出数组的大小,而普通的非数组名的指针,或者是由数组名隐式转换的指针是不会知道数组大小的。

所以可以得出以下结论:

1.数组名不是指针,仅仅是可以隐式转换为指针

2.数组名是一种特殊的数据结构,可以得出数组的大小

3.当数组名作为形参进行值传递时,将失去这种特殊的数据结构

4.数组名是一个常量





85-dify案例分享-无需OpenAI账号,Dify+Sora2工作流实战:一键生成写实动漫视频,插件+教程全解析 本文详细解析了如何利用Dify平台结合Sora2插件,搭建无需OpenAI账号的AI视频生成工作流。通过可视化拖拽配置,用户输入文本描述即可一键生成高质量的写实或动漫风格短片,极大降低了AI视频创作的技术门槛。教程涵盖插件安装、API密钥获取、工作流搭建及优化技巧,助力创作者快速实现创意。 阅读详情

相关推荐

减小伺服电机共振的方法(以松下伺服为例)

嘿 ! 我是【小黄】 , 我们又见面啦 !!! 毕竟技术只有大家交流才会进步嘛 ! 这博客是对自己学习的一点点记录和总结 ,如果您对自动控制感兴趣的话 ,可以关注一下我的动态 , 我们一起学习呀 ! 我们都还年轻 ,我们还有无限可能 。 YES ! 减小伺服电机共振的方法(以松下伺服为例)1. 准备工作:1.1.1 如何推定共振点:1.1.2 测定实操:1.1.3 总结:2. 下期预告: 在我们调试完伺服参数以后机器人运动到某个特定位置会产生振动或异响,我们要做的就是消除这个异响保..

在下小黄的博客 1万+

偏移地址范围

从书上得知 偏移地址为16位,16位地址最大寻址能力为64KB,所以一个段长度最大为64K(0H~FFFFH)8086CPU为16位 得出64K = 2^1664K=65536Byte = 2^16Byte物理地址=SA*16+EAEA的范围是0H~FFFFH(内存单元划分为:0~65535)

bypeng的专栏 3216

达梦DM8整合Seata AT模式实战:手把手教你搞定分布式事务(含源码修改避坑)

本文详细介绍了达梦DM8数据库与Seata AT模式的深度整合实战,包括环境准备、架构设计、源码适配及分布式事务落地。通过独创性源码改造,解决了Seata官方对达梦数据库AT模式支持的限制,为国产数据库在微服务架构中的应用提供了可靠的事务保障。

weixin_30764771的博客 333

[汇编语言]转移指令的原理

汇编语言 转移指令的原理

Protein_zmm的博客 1171

wsl2内核版本和模块版本不一致解决方法

** /lib/modules/…build: No such file or directory错误解决办法这篇文章历时1个月整,从4月5日一直到5月5日,这一问题才得以解决。

m0_60634555的博客 5103

洛奇 服务器文件,MabinogiG20S2 [洛奇G20服务端]

Code:Titles:>set_title /id: /add /remove Parameters for titles>set_title /id:60001 /add add devcat title>set_title /id:60001 /remove remove devcat title===========================...

weixin_30813385的博客 4307

有关汇编语言中列表文件地址偏移量和十六进制数所占字节的学习和思考

有关汇编语言中列表文件地址偏移量和十六进制数所占字节的学习和思考 地址偏移量 第12行,00000005是起始偏移量(个人认为也可以理解为执行本条语句前的所在地址),这个偏移量是指从程序起始地址开始5个字节的距离。那么这个00000005的偏移量是如何算出的呢?就要看第11行,首先明确11行和12行的00000005含义不同,前者为常数值(被mov给eax),后者为地址偏移量。第11行,起始偏移量为00000000,所以这5字节是由‘’B8 00000005‘’这个指令的执行而产生。 十六进制数所占字节

weixin_47328461的博客 1212

Android 13 SPRD 源码默认打开多用户实际无效果问题修复

【代码】Android 13 SPRD 源码默认打开多用户实际无效果问题修复。

m0_60898338的博客 449

【基础知识】数组首元素地址和数组地址

"&数组名[0]”表示的是数组的首元素地址,要注意的是,这个首元素地址是第一个元素数组的首地址。,就是数组元素的首地址,该值是一个常量,不能被修改,一定程度上等同于常量指针;)如果是p,则p+1就跳过这个数组而指向这个数组中最后一个元素。若 &p+1,则值为 p 的地址 + 40字节。若 p+1,则值为 p 的地址 + 4字节。)如果是p,则p+1指向第二个元素的地址。1、它们的地址值是一样的。

m0_56573171的博客 4304

软考高级网络规划设计师教程(第3版)

"本书是由工业和信息化部教育与考试中心组织编写的考试用书,依据《网络规划设计师考试大纲》(2026年审定通过)编写。本书分为两篇:第一篇为网络规划与设计综合知识,其中第1章介绍计算机网络基础知识,第2章介绍网络互连与互联网,第3章介绍网络规划与设计的知识和方法,第4章介绍网络资源设备,第5章介绍网络安全技术,第6章介绍标准化和网络安全法规;第二篇为案例实践,其中第7章介绍网络规划案例,第8章介绍网络故障分析与处理案例,第9章介绍网络安全部署案例,第10章介绍网络规划与设计论文写作的指导思想和写作技巧。

鹿鸣天涯 3944

【五分钟论文笔记】Vision Banana:图像生成器成为通用视觉学习器

图像生成训练可以像 LLM 预训练一样,让模型学习强大且通用的视觉表示感知即生成——将视觉任务输出参数化为 RGB 图像,是一种优雅且强大的统一框架视觉理解能力可以在不牺牲生成能力的情况下获得——两者可以共存于同一个模型。

专注:太空算力、AI infra、异构调度、大模型成本工程 232

数组地址,数组首地址,数组首元素地址的区别

声明:本文转载自博客园 原作者作者:Min 原文链接:https://www.cnblogs.com/MinPage/p/14202641.html 数组地址,数组首地址与数组首元素地址的区别1.0 理清概念2.0 代码测试2.1 静态数组2.1.0分析2.2动态内存分配2.2.0分析 1.0 理清概念 C++中的int*、int**、int&、int*&、int *a[]、int(*a)[]: int a; //a是一个int型【变量】 int *a; //a是一

drgeek的博客 4799

Python全栈入门到实战【基础篇 04】核心基础:变量与4种基础数据类型(int/float/str/bool)

本文介绍了Python编程中的变量和四种基础数据类型,作为后续所有语法的入门前提。变量是数据的“容器”,解决数据复用问题,而数据类型决定数据能进行的操作。文章详细讲解了变量的定义语法、命名规则(强制语法和推荐风格)、赋值与修改原理,并通过实操示例展示其应用场景。正确使用变量可以提升代码复用性、简化修改并增强可读性,是编程效率的核心原则。掌握这些基础知识能避免90%的新手语法错误,为学习更复杂的Python语法打下坚实基础。

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 4325

27 数组的本质分析

一、数组的概念  数组的大小: 编程实验:数组的初始化 #include &lt;stdio.h&gt; int main() { int a[5] = {1, 2}; //int a[5] = {0}; //编译器会将未指定的元素初始化为0 int b[] = {1, 2}; printf("a[2] = %d\n", a[2]); ...

渲染引擎开发 204

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

数组首元素地址、数组首地址、整个数组地址的分析

现在定义一个char a [10];的数组,下面对这几个名词进行分析: 1、数组首元素地址 :该数组有10个元素,数组首元素即a[0],取的是该元素的地址。 2、数组首地址:就是数组名字a的地址。 3、整个数组地址:就是整个数组的地址,取地址&amp;a。 下面的代码进行测试: #include &lt;stdio.h&gt; #include &lt;stdlib.h&g...

嵌入式 2万+

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

C语言——数组的首元素地址和数组地址

数组地址、数组首元素地址之间的区别

xuandlu的博客 6191

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C语言:数组的地址和数组首元素的地址的区别

当我们谈论数组的地址时,我们通常指的是整个数组的起始地址,也就是数组第一个元素的地址。例如,如果你有一个指向10个整数的数组的指针int (*p)[10],*p将得到一个包含10个整数的数组。数组的地址:它是指向整个数组的指针,其类型是数组类型(例如,int (*p)[10]表示一个指向含有10个整数的数组的指针)。当你解引用数组首元素的地址时,你会得到数组的第一个元素。数组首元素的地址:它是指向数组第一个元素的指针,其类型是该元素的类型(例如,int *p表示一个指向整数的指针)。

2203_75904043的博客 1265

还搞不清楚数组地址,数组首元素地址和指针的关系?一篇带你从入门到精通

在C语言编程学习过程中,不少老铁会特别头大这个数组和指针之间的关系。例如arr[],这个arr一会又是代表数组首元素地址,一会又是代表数组地址,甚至有的老铁还会疑惑,啥是数组地址呀!??那么这篇文章将会带你彻底搞懂这二者之间的关系。

weixin_57537814的博客 4197

数组地址计算

1、一维数组 设数组为A = a1,a2,a3,a4…ai…an; 每个数据元素占d个存储单位,则元素a[i]的存储地址为 Loc(A[i])=Loc(A[1])+(i−1)∗dLoc(A[i])=Loc(A[1])+(i−1)∗d Loc(A[i]) = Loc(A[1]) + (i-1)*dLoc(A[i])=Loc(A[1])+(i−1)∗d Loc(A[i])=Loc(A[1])+(i−1...

ppBlog 4861

数组的寻址

数组的顺序存储表示和实现-数组的寻址 两种顺序映象的方式 以行序为主序(低下标优先) 以列序为主序(高下标优先) 可用下标值随机的访问该数组的任意一个元素。 计算数组元素存储地址的公式称为寻址公式。 一维数组寻址公式 若一维数组的下标下界为LB,上界为UB,每个元素占用S个存储单元,第一元素(其下标为LB)的地址为LOC(LB),下标为i的数组元素A[i]的地址为LOC(i),则计算LOC(i)的寻址公式为: LOC(i)=LOC(LB)+(i−LB)×S 例1: 若一维数组a[5], 每个元素占用4个存储

weixin_43055166的博客 4514

一维数组数组名、首元素地址以及二维数组首元素地址,第i行元素地址,元素地址等等的区别(超详细)

1、在正式介绍知识点之前,我们应该明确一些基本知识。 (1)一般情况下数组名都是代表首元素的地址,除了以下两种情况: <1>sizeof(数组名) //注意:()里仅有数组名,不能有其它的东西 <2>&数组名 (2)sizeof()函数的作用 sizeof()计算的是对象所占内存的大小,单位为字节 (3)strlen()函数的功能 strlen()计算从起始地址开始往后数,直到遇到'\0'才停止,并...

yakiyakiya的博客 5646

C语言中对于基本指针,数组地址与首元素地址区别的理解

C语言指针基础的入门感悟(一),拒接枯燥,拒绝不好理解。

yinyoushiren_wb的博客 1823

C语言数组名是首元素地址还是数组的地址?

c语言数组名到底是首元素地址还是数组的地址?

如果这是最后一页 能否让我把故事重写 2510

数组的地址和数组首元素地址

来看一道简单的笔试题 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { int a[5] = { 1, 2, 3, 4, 5 }; int* ptr = (int*)(&a + 1); printf("%d,%d", *(a + 1), *(ptr - 1)); return 0; } //程序...

qq_43808700的博客 4047

数组的首地址和数组首元素的地址

#include<stdio.h> void main () { int a[10]={1,2,3,4,5,6,7,8,9,10}; int *p1; int (*p2)[10]; p1=a; p2=&a; printf("%d\n",*p1); printf("%d\n",*(int *)p2);

a1066570234的博客 1万+

关于数组名:数组名是数组首元素的地址

为什么数组名表示的是数组首元素的地址捏^_~ 真的不来看看嘛(╹ڡ╹ )

weixin_62234287的博客 7969
上一篇: 在QT4中处理windows消息
下一篇: 关于Qt使用QSqlQuery执行sql语句时出现out of memory的问题
碎炎
博客等级 码龄16年 85粉丝 61原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值