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

供稿:hz-xin.com     日期:2025-01-14
从编译器角度分析C语言中数组名和指针的区别

从编译生成的角度来说
数组名 没有本身的存储空间,其只是一个地址。 代表数组的首地址。
于是 数组名的值 不可能被改变。

而指针 是一个变量 有自身的存储空间
可以被改变值 执行数学操作。

从汇编角度两者没有区别,指针就是存储地址,当你使用引用的时候,最终也是通过地址去访问变量,你可以进入VS的调试模式然后看反汇编代码

int a;

int *p = &a;
*p = 4;

int &b = a;
b = 3;

上面这两种方式你看汇编代码就知道,都是通过 a的地址去修改a的值

比如定义

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

汇编后 

(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";1212

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

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

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

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

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



从汇编语言的角度看清数组名和指针变量的区别
(2)名称(标号)的区别 从汇编中可以看出,CPU 只能直接操作固定大小单元的数据(字节,字),因为数据的操作是要经过寄存器的,寄存器只能是8位寄存器(AL、BL…)、16位寄存器(AX、BX…)…指针变量p 中存的是地址值,只需要分配 dw 大小(事实上在64位系统中并不是2个字节)。所以,指针变量...

a是数组名p是指针那*p=a和p=a有什么区别
首先你要明白,a是个十六进制的地址常量,a其实就是a[0]这个数值的地址,也就是a=&a[0] , p这个字母一般把它定义为地址, *p就是p指向的数值的值,你却把一个值定义为一个地址(*p=a 这种写法是错误的),不符合常理。不能这样定义, 只可定义为p等于a ,也就是*p等于a[0],p指向a...

c语言中函数返回值可以是数组、字符串和结构体吗?
\/\/语法编码规则的角度看 ANSI C语言标准,明确规定 数组类型和函数类型不可以做为返回值。解决这种返回值的方法是通过指针来间接返回,即使用数组指针和函数指针。这可以做为c语言引入指针的另一个理由。结构体类型可以做为返回值,我猜测C语言设计者当时引入struct结构体的概念,目的是为了增加一种建立C...

关于二维数组名的问题。
把指针当成一个“标签”,是汇编语言上的实现;而你这个好学的学生要是知道系统栈是神马的话,请继续看下面的东西:理论上,指针常量要比标签要多存放一个地址;即:标签->指针->地址和标签->地址的区别;而神马标签都在系统栈中占据着一个指针以上的空间。而神马指针都在程序中占据着一个指针的空间。

指针地址数据为0读取错误
) 想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。 从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单! 指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。” 但我又不得不承认: 有那么些人喜欢或者适合用“先具体再抽象”的方法学习...

指针和数组的区别
指针和数组的区别是指针变量用于保存数据的地址,数组用于直接保存数据。指针一般指向一个函数或一个变量,在信息工程中是一个用来指示一个内存地址的计算机语言的变量或中央处理器(CPU)中的寄存器(Register)。指针一般出现在比较近机器语言的语言,如汇编语言或C语言。面向对象语言如Java一般避免用指针,而是...

为什么内联汇编不把字符串名当作指针看待?
不可能当指针看的,传递a的指针,当然用lea命令。

怎样理解这句话,我是c语言初学者!
第二个a[1] 就是11110000+8 依次类推,整形就是这样存放的。地址里面存放这值。也就是传址调用 , 没必要传址吧?a[1]比如这样,有必要传值? 哈哈,说的太郁闷了,充分理解啦。 虽然C语言注重指针,但是这句话,说的很扯蛋。很难理解,让人无法理解的,根本就不是话了。

C语言数组名
这些按序排列的同类数据元素的集合称为数组。在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以...

C语言如何为结构体中的某个属性赋值
C语言中,数组间不能相互赋值——这是历史遗留问题,当年在B语言中,数组名和指针名是没有区别的(除了数组名定义时自动为数组分配内存),数组名可以指向别的对象或数组。换句话说,数组名之间的赋值是浅赋值。后来C语言的设计者发现这种规则在C语言行不通,但是C语言的设计者又不想破坏对B语言的兼容...