从汇编语言的角度看清数组名和指针变量的区别

C语言数组名与指针的编译器实现差异 在C语言底层实现中,数组名和指针虽然都可以表示内存地址,但编译器处理机制存在本质区别。从计算机体系结构角度看,数组名是编译期确定的地址常量,直接对应符号表中的固定地址;而指针是运行时动态计算的地址变量。这种差异导致两者在符号表管理、代码生成和指令优化等方面表现不同。理解这些底层原理对编写高性能代码尤为重要,特别是在嵌入式开发、编译器优化等场景中。通过分析数组访问的1次访存与指针访问的2次访存差异,开发者可以更好地进行性能敏感场景的选择。现代编译器对数组访问会进行常量传播、循环展开等优化,这些特性在系统编程和 阅读详情

当初学c语言总感觉数组名和指针之间有种说不清道不明的关系,两者很像,但是又有着解释不清的区别。

比如定义:

char a[]=”hello”;
char *p=”hello”;

同:

都可以用名字输出字符串首地址
printf(“%p %p\n”,a,p);

都可以用名字输出字符串内容
printf(“%s %s\n”,a,p);

都可以用下标操作
a[1] 和 p[1]都对应字符串第1个字符

最大的不同:

p + 1 和 a+1 都对应第一个字符的地址

但是:

可以执行 p = p + 1 或 p = a + 1;
却不可以执行 a = a + 1;
即,赋值运算的左操作数不能是数组名

分析

为了方便,用8086汇编来说明一下:

  数组名和变量名都可以看作汇编语言里的标号,如下:

只需要关注第9、10、20行即可
这里写图片描述

(1)对应的内存空间大小不一样

第9行定义了6个字节的大小(即数组),第10行定义了2个字节(即标号p对应的空间)。

char *p = “hello”;
虽然 a和p 指向的都是一个字符串,但是 a 对应的空间中直接存储了字符串“hello”( ‘$’是字符串结束符,相当于‘\0’), 而p 对应的空间中存储的是字符串的首地址。

p = “hello” 相当于汇编代码中的第20行,获取到”hello”的首地址存到p中。(间接指向字符串)

这也就说明了为什么 sizeof(a) 和 sizeof(p) 计算出的大小是不一样的。

(2)名称(标号)的区别

从汇编中可以看出,CPU 只能直接操作固定大小单元的数据(字节,字),因为数据的操作是要经过寄存器的,寄存器只能是8位寄存器(AL、BL…)、16位寄存器(AX、BX…)…

指针变量p 中存的是地址值,只需要分配 dw 大小(事实上在64位系统中并不是2个字节)。所以,指针变量可以被操作,加、减、赋值运算等。
比如:p = p + 1 (地址值加1)
add p,1

但是字符串是单个字符组成的,每个字符都占8个字节单元,CPU是无法直接对这么一大块内存进行操作的,比如“hello”+1 你觉得这个值该是什么呢。对于字符串是利用首地址进行操作的,根据标号a 可以获取到字符串的首地址,a+n 可以获取到相对首地址偏移n 的地址。使用offset 获取有效地址,如 mov p,offset a+3 ,等价于 p=a+3.

所以汇编中,p+3 和 offset a+3 是等价的,仅仅是a+3对应的是相对首地址偏移量为3的字符。

p = p+1
可以用add p,1 表示;

但是 a=a+1
若用add a,1 表示,则实际含义是:a 是首地址,对应第0个字符’h’, 加1 则表示第0个字符加1,字符串变成了”iello”。这其实是 a[0] = a[0]+1。
用汇编并不能实现 地址值+1 然后赋值到 a 中的效果,所以不能执行a = a+1 。

下标操作就是相对于标号偏移n对应的内存单元,a[2],p[2] 即a+2和p+2对应的单元(这里是一个字节)。

(3)用常量字符串初始化字符数组和指针变量

char a[]="hello";
char  *p="hello";

这两条语句似乎没啥区别,都是初始化了一个字符串。但是,经过上面的分析可以看出这两条语句的区别是很明显的。

字符数组的初始化其实是定义了6个字节的内存空间,
然后把”hello”的每个字符依次放进去,a[0]=’h’,a[1]=’e’。。。

而指针变量的初始化是,先定义了比如2个字节的单元,然后把常字符串的首地址存进去。

所以,可以用下标操作,如 a[1] = ‘b’ 来更改字符串的内容。 但是,指针变量是间接的指向常字符串,他是通过常字符串的地址来操作字符串,在c语言中,常字符串是只读的,不允许修改,一般编译的时候把常字符串放进了文本段中。所以,不能通过指针变量来修改常字符串,比如 p[1] = ‘b’ 。他产生的结果是未定义的,未定义即编译器可能报错或产生了异常结果。

另外:
char *p = NULL;
p = “hello”;
这样也不可以修改常字符串,道理和上面是一样的。

以上是我在学习了汇编语言后的一些想法,如有疑问或错误还望指出。

深入探索前端调试神器vConsole vConsole作为一款前端调试神器,为前端开发者提供了一个便捷的调试解决方案。通过本文的介绍和示例,相信你已经对vConsole有了更深入的了解。然而,vConsole的功能远不止于此,它还有许多高级用法和技巧等待你去发掘。讨论:你在前端开发中是如何使用vConsole的?你有没有发现vConsole的一些隐藏功能或技巧?欢迎在评论区分享你的经验和见解!💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面! 阅读详情

相关推荐

国产数据库迁移必看:达梦到ES的CDC方案优化全记录(含完整代码)

本文详细记录了从达梦数据库到Elasticsearch的CDC方案优化全过程,涵盖触发器方案局限性、Debezium架构优势及完整代码实现。通过Flink集成和性能调优,实现毫秒级延迟同步,显著降低数据库负载,为国产数据库迁移提供可落地的技术方案。

weixin_29079671的博客 500

汇编 —— 数组

文章目录基本原则指针运算练习题练习题答案嵌套数组练习题练习题答案参考文献 基本原则 对于数据类型T和整型常数N,声明如下即为数组: T a[N]; 起始位置表示为Xa,这个声明有两个效果: 在内存中分配一个sizeof(T)*N字节的连续的区域 引入标识符a,可以用a来作为指向数组开头的指针,这个指针的值就是Xa 而在x86-64中的内存引用指令可以用来简化数组访问,比如说,E是一个int型的数组,而我们想要计算E[i],假设E的地址放在寄存器%rdx中,i 放在寄存器%rcx中,那么访问E[i]的汇

0 error(s) 3965

IC618新手避坑指南:从零在Linux上配置Cadence Virtuoso环境(含cds.lib文件详解)

本文详细介绍了在Linux系统上配置Cadence Virtuoso IC618环境的完整指南,特别针对新手常见问题提供解决方案。重点解析了cds.lib文件的关键配置,包括库路径定义和工艺库管理,并分享了高效工作流设置和典型问题排查技巧,帮助工程师快速搭建稳定的EDA设计环境。

weixin_26805597的博客 556

汇编学习--数组

数组是相同数据类型的元素的集合,它们的内存中按顺序连续存放在一起。在汇编状态下访问数组一般是通过基址加变址寻址实现的。 0x01 先找一个数组访问的C语言代码 #include<stdio.h> int main() { static int a[3]={0x11,0x22,0x33}; int i...

gclome的博客 1万+

Zemax非序列模式新手入门:从零搭建一个抛物面反射镜系统(含灯丝光源与探测器设置)

本文详细介绍了如何在Zemax非序列模式下从零搭建抛物面反射镜系统,包括灯丝光源配置、反射镜建模和探测器设置等关键步骤。通过实战指南,帮助光学设计新手快速掌握非序列模式的应用技巧,特别适合处理复杂光线传播场景如反射镜系统和杂散光分析。

weixin_28717431的博客 436

高通ISP模块全解析:从Raw到JPEG的18个关键处理步骤(附避坑指南)

本文全面解析高通ISP模块从Raw到JPEG的18个关键处理步骤,涵盖原始数据预处理、色彩科学处理链、画质增强与降噪等核心环节。通过实战调优经验,揭示ISP架构中的技术原理与工程实践要点,帮助开发者避免常见问题,提升移动影像处理质量。

weixin_30399155的博客 360

汇编学习笔记——伪指令

伪指令 定义:没有对应机器码的指令,最终不被CPU所执行,而是由编译器执行的指令。编译器根据伪指令来进行相关的编译工作。 示例1:一段汇编程序中的伪指令示例 PS:伪指令在debug中直接执行汇编代码是不需要的,但若要将汇编程序交由编译器执行,则是必要的。 段定义 定义:一个汇编程序是由多个段组成的,这些段被用来存放代码、数据或当作栈空间来使用。格式为:段名 segment表示段的开始;段名 ends表示段的结束。 示例:完整的汇编程序 PS1:一个有意义的汇编程序中至少要有...

aketoshknight的博客 2684

具身智能ACT模型在lerobot机械臂上的实践与优化

本文详细介绍了如何在低成本lerobot机械臂上实践与优化具身智能ACT模型。从环境搭建、数据采集到模型原理与代码实战,提供了完整的入门指南。重点分享了通过数据增强、混合开源数据集及模型微调等策略,有效提升模型在抓取放置任务中的泛化能力与鲁棒性,为机器人学习爱好者提供了宝贵的实战经验。

weixin_29081703的博客 169

【通过汇编语言理解C语言指针】

汇编推导C语言指针

weixin_44821965的博客 752

遇到问题--OpenClaw--API rate limit reached. Please try again later429 您的账户已达到速率限制,请您控制请求频率

OpenClaw调用glm-4.7-flash模型时触发智谱AI平台429速率限制错误。分析发现当前重试策略采用固定间隔(7-11秒)导致连续失败,且未记录关键响应头信息。解决方案分三步:1)开启响应头日志获取配额详情;2)将重试策略改为带抖动的指数退避(初始1秒,最大60秒);3)在网关层实现令牌桶限流主动控制请求频率。需特别注意令牌配额(TPM)可能比请求次数(RPM)更早触达限制。

直到世界的尽头 2623

Transformer 跨界物理建模:探索模拟动态物理系统方法与实践(PINN、流体力学、有限元)

是一个由 Nicholas Zabaras 团队开发的开源项目,托管于 GitHub,旨在将 Transformer 模型(最初在自然语言处理领域大获成功)应用于物理系统的建模与预测。该项目基于论文 ​*“Transformers for Modeling Physical Systems”*​(Neural Networks, 2022),探索了深度学习中的 Transformer 架构如何通过自注意力机制和 Koopman 嵌入来模拟动态物理系统。

源代码杀手的博客 1191

汇编语言:以ARRAY为首地址的内存单元中,存放5个8位的不带符号数,找出5个数中的最大数,并将结果存入RESULT字节单元中。

以ARRAY为首地址的内存单元中,存放5个8位的不带符号数,找出5个数中的最大数,并将结果存入RESULT字节单元中。

aa543928678的博客 1763

关于 SAP UI5 应用 url 中的特殊符号 # 的作用介绍

符号在 SAP UI5 的 URL 中不仅仅是一个分隔符,更是动态路由、状态管理和深链接的关键所在。通过合理使用,开发者可以实现高效、流畅的用户体验,同时保持系统的可维护性和扩展性。通过 SAP UI5 提供的灵活路由机制,企业应用可以轻松实现复杂导航需求,同时为用户提供直观的交互体验。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 412

从编译器角度分析C语言中数组名和指针的区别

数组名和指针是两个往往很容易让人们混淆的概念,很多人以为数组名就是一个指针,也有很多人知道数组名不同于指针但是仅知道数组名的值不能像指针一样改变,例如你可以写出下面这样的代码: int *p; p++; 却不能写这样的代码: int a[]; a++; 那么数组名跟指针之间到底有什么区别呢? 第一,在声明上,除了作为函数

__清__风__ 3136

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

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

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

从汇编的角度来看C语言标识符以及对数组名取地址为什么与数组名的值相同

我之前一直有一个疑问,对数组名取地址和数组名的值为什么是一样的。单纯听别人口头讲述这个东西其实我觉得还是有点难以理解,我觉得从汇编的角度来看待这个问题,非常好理解。 int main() { int a = 1; int c[10] = {1,2,3,4,5,6}; return 0; } 上面这样的一段简单的代码,我们从汇编的角度来看一些,首先要说明的是,c语言中...

P19777的博客 1083

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

欢从汇编角度看待数组名---纸上得来终觉浅,绝知此事要躬行

本文中心内容:1.数组名代表的是一个数据结构对象 2.数组名可以看成一个常量指针但实际并不是一个指针,3.指针存放的是偏移量(一个是对象,一个是可以看成指针但实际并不是指针,而另一个又是存放)。 刚上大学学C++的时候经常在网上看到文章说数组名就是指针。。然后就有人反驳,然后就在评论里面‘吵’个不停,’谁也不让谁。。。。无语 废话少说: 欲看懂后面的内容先补充几条AT&amp;amp;T形式的汇编语句: ...

qq_34384524的博客 409

转载加自己的见解 之从编译器角度分析C语言中数组名和指针的区别

数组名和指针是两个往往很容易让人们混淆的概念,很多人以为数组名就是一个指针,也有很多人知道数组名不同于指针但是仅知道数组名的值不能像指针一样改变,例如你可以写出下面这样的代码: [cpp] view plaincopyprint? int *p;  p++;   int *p; p++;    却不能写这样的代码: [cpp] vi

magento 1310

从编译器角度分析C语言中数组名和指针的区别--转

从编译器角度分析C语言中数组名和指针的区别 数组名和指针是两个往往很容易让人们混淆的概念,很多人以为数组名就是一个指针,也有很多人知道数组名不同于指针但是仅知道数组名的值不能像指针一样改变,例如你可以写出下面这样的代码: int *p; p++; 却不能写这样的代码: int a[]; a++; 那么数组名跟指针之间到底有什么区别呢? 第一,在声明上,除了作为函数参数的数组...

iteye_582的博客 307
上一篇: 学习红黑树
下一篇: 进程间通信ipcs、ipcrm命令
lwoyvye
博客等级 码龄12年 81粉丝 70原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值