关于数组的元素,以汇编的角度我这么理解对么?
本帖最后由 竹逸 于 2022-8-27 08:25 编辑a,其中[ ]表示一个内存单元,5表示的是该内存单元的偏移地址(相对于基址a的偏移地址)
数组名本质上是一个基址,是段首地址(一个段中连续内存单元的起始地址),我们可以通过数组名+下标索引的方式来定位各个元素,即通过基址和相对于基址的偏移地址的方式来定位各个元素(内存单元)
数组元素也是一个变量,我理解的变量是一块内存单元,变量名则是给该内存单元的取名,变量的地址则是该内存单元的地址值 本帖最后由 jackz007 于 2022-8-27 00:00 编辑
没错,你的理解很对。
int a ;
这条语句分配 4 x 5 = 20 个字节的存储单元,并定义了一个常数指针 a 指向这个存储区的起始地址。
a = 8 ;
这条语句会在从地址 a 起算,偏移为 8 的位置处的连续 4 个字节单元中,存入一个整型数 8(08 00 00 00)。 jackz007 发表于 2022-8-26 23:58
没错,你的理解很对。
这条语句分配 4 x 5 = 20 个字节的存储单元,并定义了一个常数 ...
关于变量和数组的区别我这么理解应该没错吧{:5_108:}
变量名是一个标识符,它标记了内存中某快内存单元,通过变量名也就是通过标识符可以定位被标记的内存单元,给变量赋值则是给被标记的内存单元写入数据。变量名可以理解为给该内存单元的取名,变量的地址则是该内存单元的地址值(下标索引)
数组名也是一个标识符,它同样也是标记了内存中某快内存单元,它和变量本质上没有区别,有区别的地方在于它们的值不同,变量的值是一个简单的值,可以是整形,字符型等,而数组名的值是一个内存地址(指针),它指向的是变量的地址,而不是变量的值。
竹逸 发表于 2022-8-28 13:54
关于变量和数组的区别我这么理解应该没错吧
变量名是一个标识符,它标记了内存中某快内存单 ...
没错。 jackz007 发表于 2022-8-28 14:05
没错。
既然数组名也是一个标识符,它同样也是标记了内存中某块内存单元,通过数组名也就是通过标识符可以定位被标记的内存单元,那这个被标记的内存单元里存储的应该是另一个内存地址才对
可如下图所示
为啥被标记的内存单元地址和它存储的值(另一个内存地址)是一样的,难道说这个被标记的内存单元里存储的是它本身的地址? 竹逸 发表于 2022-8-28 14:45
既然数组名也是一个标识符,它同样也是标记了内存中某块内存单元,通过数组名也就是通过标识符可以定位被 ...
a 是常量指针,& a 就是 a 本身。 jackz007 发表于 2022-8-28 14:05
没错。
通过实验,它果然是记录的自身的地址{:5_97:}
这自己记录自己就很狗{:5_99:} 竹逸 发表于 2022-8-28 14:45
既然数组名也是一个标识符,它同样也是标记了内存中某块内存单元,通过数组名也就是通过标识符可以定位被 ...
忘了吗?
数组的名字是数组第0个元素的地址
就是 a == &a
&a 是整个数组的地址
&a 和 a 的值是一样的,但是类型不一样
人造人 发表于 2022-8-28 15:03
忘了吗?
数组的名字是数组第0个元素的地址
就是 a == &a
你看我上面的回复,数组名本身是有自己的地址的,这个它本身的地址存储的是数组的首地址,只不过它本身地址里存储的是它本身 看汇编代码么
a&a&a 这三个的值都是一样的,都是leal -0x20(%ebp),%eax
int main(void) {
118d: 8d 4c 24 04 leal 0x4(%esp),%ecx
1191: 83 e4 f0 andl $0xfffffff0,%esp
1194: ff 71 fc pushl-0x4(%ecx)
1197: 55 pushl%ebp
1198: 89 e5 movl %esp,%ebp
119a: 53 pushl%ebx
119b: 51 pushl%ecx
119c: 83 ec 20 subl $0x20,%esp
119f: e8 ec fe ff ff calll1090 <__x86.get_pc_thunk.bx>
11a4: 81 c3 50 2e 00 00 addl $0x2e50,%ebx
11aa: 65 a1 14 00 00 00 movl %gs:0x14,%eax
11b0: 89 45 f4 movl %eax,-0xc(%ebp)
11b3: 31 c0 xorl %eax,%eax
int a = {1, 2, 3, 4, 5};
11b5: c7 45 e0 01 00 00 00 movl $0x1,-0x20(%ebp)
11bc: c7 45 e4 02 00 00 00 movl $0x2,-0x1c(%ebp)
11c3: c7 45 e8 03 00 00 00 movl $0x3,-0x18(%ebp)
11ca: c7 45 ec 04 00 00 00 movl $0x4,-0x14(%ebp)
11d1: c7 45 f0 05 00 00 00 movl $0x5,-0x10(%ebp)
printf("%p, %p, %p\n", a, &a, &a);
11d8: 8d 45 e0 leal -0x20(%ebp),%eax
11db: 50 pushl%eax
11dc: 8d 45 e0 leal -0x20(%ebp),%eax
11df: 50 pushl%eax
11e0: 8d 45 e0 leal -0x20(%ebp),%eax
11e3: 50 pushl%eax
11e4: 8d 83 14 e0 ff ff leal -0x1fec(%ebx),%eax
11ea: 50 pushl%eax
11eb: e8 60 fe ff ff calll1050 <printf@plt>
11f0: 83 c4 10 addl $0x10,%esp
printf("%x, %p, %x\n", *a, *&a, *&a);
11f3: 8b 55 e0 movl -0x20(%ebp),%edx
11f6: 8b 45 e0 movl -0x20(%ebp),%eax
11f9: 52 pushl%edx
11fa: 8d 55 e0 leal -0x20(%ebp),%edx
11fd: 52 pushl%edx
11fe: 50 pushl%eax
11ff: 8d 83 20 e0 ff ff leal -0x1fe0(%ebx),%eax
1205: 50 pushl%eax
1206: e8 45 fe ff ff calll1050 <printf@plt>
120b: 83 c4 10 addl $0x10,%esp
return 0;
120e: b8 00 00 00 00 movl $0x0,%eax
}
1213: 8b 55 f4 movl -0xc(%ebp),%edx
1216: 65 2b 15 14 00 00 00 subl %gs:0x14,%edx
121d: 74 05 je 1224 <main+0x97>
121f: e8 0c 00 00 00 calll1230 <__stack_chk_fail_local>
1224: 8d 65 f8 leal -0x8(%ebp),%esp
1227: 59 popl %ecx
1228: 5b popl %ebx
1229: 5d popl %ebp
122a: 8d 61 fc leal -0x4(%ecx),%esp
122d: c3 retl
122e: 66 90 xchgw%ax,%ax
竹逸 发表于 2022-8-28 15:08
你看我上面的回复,数组名本身是有自己的地址的,这个它本身的地址存储的是数组的首地址,只不过它本身地 ...
那么这个地址存储在什么地方?数组第0个元素的位置?
数组第0个位置存储的是数字1,不是数组的地址
这个数组的地址是 不存储的
你非要说存储的话,那就是存储在编译器的内部
int a = {1, 2, 3, 4, 5}; 竹逸 发表于 2022-8-28 15:08
你看我上面的回复,数组名本身是有自己的地址的,这个它本身的地址存储的是数组的首地址,只不过它本身地 ...
a&a&a
这3个的值不需要内存地址来存储
这3个的值存储在编译器的内部,程序运行的时候,内存中不存储这3个的值
人造人 发表于 2022-8-28 15:21
a&a&a
这3个的值不需要内存地址来存储
这3个的值存储在编译器的内部,程序运行的时候,内存中不 ...
等等,我先捋捋{:10_266:} 人造人 发表于 2022-8-28 15:21
a&a&a
这3个的值不需要内存地址来存储
这3个的值存储在编译器的内部,程序运行的时候,内存中不 ...
我知道我想错了,按照我的思维逻辑是这样的,
数组名是不是一个指针变量?如果是,那指针变量也是一个变量,在声明的时候CPU就会为它开辟一块内存空间,只不过这块内存空间里存储的是内存地址,假设CPU为指针变量分配的内存空间的地址是18FF34,那这块内存地址里存储的指针是它本身,即18FF34里存储的内存地址是18FF34,*a取的是指针变量18FF34里存储的18FF34的值,因为他里面存储的是自身,也就是取的是18FF34,&a取的是指针变量a本身的地址,*&a取的是它自身地址里存储的值,也是它里面存储的内存地址18FF34,到这里出问题了,那第一个元素的值存储在哪里?既然18FF34里存储的是18FF34,那第一个元素呢{:10_266:} 竹逸 发表于 2022-8-28 16:00
我知道我想错了,按照我的思维逻辑是这样的,
数组名是不是一个指针变量?如果是,那指针变量也是一个 ...
int a = {1, 2, 3, 4, 5};
如果编译器打算把这个数组放在内存地址 18FF34 开始的位置
那么 a &a&a 这3个的值都是 18FF34,不存在谁保存谁的问题
这样理解也许更合适,如果你在代码中出现了a,那么编译器直接把这个a换成18FF34
你写&a也一样,直接换成18FF34
&a 也是直接换成 18FF34
不存在谁保存谁的问题,谁也不保存谁
只要编译器看见了这3个,直接换成 18FF34
人造人 发表于 2022-8-28 16:21
这样理解也许更合适,如果你在代码中出现了a,那么编译器直接把这个a换成18FF34
你写&a也一样,直接换成18 ...
令我疑惑的是这个*a和*&a,如果a和&a没区别,那为啥用取值运算符得到的一个是值,另一个却是址{:10_258:} 竹逸 发表于 2022-8-28 16:32
令我疑惑的是这个*a和*&a,如果a和&a没区别,那为啥用取值运算符得到的一个是值,另一个却是址
如果a和&a没区别
谁说a和&a没区别,a和&a是有区别的
a是数组第0个元素的地址,&a是整个数组的地址
这个区别体现在对这个地址进行运算的时候
他们的值是一样的,但是类型不一样
记住,类型不一样
#include <stdio.h>
int main(void) {
int a = {1, 2, 3, 4, 5};
printf("%p\n", &a + 1);
printf("%p\n", a + 1);
return 0;
}
本帖最后由 竹逸 于 2022-8-28 19:18 编辑
人造人 发表于 2022-8-28 16:45
如果a和&a没区别
谁说a和&a没区别,a和&a是有区别的
a是数组第0个元素的地址,&a是整个数组的地址
我回来了,不知道怎么就睡着了{:5_99:} 我运行了你的代码
得到的结论是,数组名a其实是数组的起始地址,同时也是第一个元素的内存地址,然后a+1,a是指针,1是数值,类型不同的相加运算,发现+1后它指向的是第二个元素的内存地址,那这个+1的操作是下标索引值+1,指向的是下一个元素,所以加了4个字节的长度,最后&a+1,&a取出的是整个数组的内存地址,+1后的值是加14H字节的长度,刚好是整个数组的长度,那这个+1的操作,指向的就是下一个数组的起始地址了
页:
[1]
2