IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 通过汇编分析数组名与指向数组的指针 -> 正文阅读

[C++知识库]通过汇编分析数组名与指向数组的指针

数组名是指向数组的指针吗

记得学习C语言的时候,有这样一个说法"数组名实际就是一个指向数组首地址的指针常量",
那么对数组名取地址和对数组第1个元素取地址 必然得到相同结果

char p2[20];
printf("p2: %08x, p2[0]: %08x, p2[19]: %08x\n", (int)&p2, (int)&p2[0], (int)&p2[19]);
// 本机输出 p2: 0019ff18, p2[0]: 0019ff18, p2[19]: 0019ff2b

可以看到&p2 == &p2[0]

那指向数组的指针跟数组名的使用一样吗

由于数组还可以通过new来得到,char* p = new char[20],p是一个指向数组的指针,既然p和p2都是指向数组的指针是否意味着已知&p2 == &p2[0] 一定有 &p == &p[0]呢?

    char * p = new char[20];
    printf("p: %08x, p[0]: %08x, p[19]: %08x\n", (int)&p, (int)&p[0]);
    
    char p2[20];
    printf("p2: %08x, p2[0]: %08x, p2[19]: %08x\n", (int)&p2, (int)&p2[0], (int)&p2[19]);
    // 本机输出
    // p: 0019ff2c, p[0]: 007e49e0, p[19]: 004010f0
    // p2: 0019ff18, p2[0]: 0019ff18, p2[19]: 0019ff2b

可以看到&p2 == &p2[0] 但是 &p != &p[0]

来看看汇编里都干了啥

为什么会这样呢?我们修改一下代码看一下汇编输出

这里涉及到两条汇编指令lea 和 mov 来看一下wikibook上的解释

  • mov stands for move. Despite its name the mov instruction copies the src operand into the dest operand. After the operation both operands contain the same contents.
  • lea stands for load effective address. The lea instruction calculates the address of the src operand and loads it into the dest operand.
  • Load Effective Address calculates its src operand in the same way as the mov instruction does, but rather than loading the contents of that address into the dest operand, it loads the address itself. lea和mov用同样的方法计算操作数,但lea将计算出的地址存入目标,mov将该地址上的内容存入目标
6:    int main(int argc, char* argv[])
7:    {
00401010   push        ebp
00401011   mov         ebp,esp
00401013   sub         esp,60h
00401016   push        ebx
00401017   push        esi
00401018   push        edi
00401019   lea         edi,[ebp-60h]
0040101C   mov         ecx,18h
00401021   mov         eax,0CCCCCCCCh
00401026   rep stos    dword ptr [edi]
8:        char * p = new char[20];
00401028   push        14h
0040102A   call        operator new (00401090)
0040102F   add         esp,4
00401032   mov         dword ptr [ebp-20h],eax
00401035   mov         eax,dword ptr [ebp-20h]
00401038   mov         dword ptr [ebp-4],eax   // p本身是一个变量在栈上,它的地址&p是也一个数值,这个数值在ebp-4,   new出来数组的地址在堆上,数组的地址需要放在变量本身占据的那块内存dword ptr [ebp-4]中
9:        int tmp = (int)&p;
0040103B   lea         ecx,[ebp-4]  // lea取的是 ebp-4的变量p的地址值
0040103E   mov         dword ptr [ebp-8],ecx
10:       tmp = (int)&p[0];
00401041   mov         edx,dword ptr [ebp-4] // mov取的是[ebp-4]指向存储单元中的内容, 这里编译器识别出p[0]是数组第1个元素,取的是变量p指向数组的地址
00401044   mov         dword ptr [ebp-8],edx
11:       p[0] = 3;
00401047   mov         eax,dword ptr [ebp-4]  // 在给p[0] 赋值时先得到真正的堆上的地址值,再将数据存入该地址空间
0040104A   mov         byte ptr [eax],3
12:       //printf("p: %08x, p[0]: %08x, p[19]: %08x\n", (int)&p, (int)&p[0]);
13:
14:       char p2[20];
15:       tmp = (int)&p2;
0040104D   lea         ecx,[ebp-1Ch]   // p2在栈上 p2本身的地址值在ebp-1ch 它本身的地址值就是数组的地址
00401050   mov         dword ptr [ebp-8],ecx
16:       tmp = (int)&p2[0];
00401053   lea         edx,[ebp-1Ch]   // 同样
00401056   mov         dword ptr [ebp-8],edx
17:       p2[0] = 3;
00401059   mov         byte ptr [ebp-1Ch],3      // 在给p2[0]赋值时 直接使用地值值即可,注意与p[0]=3的区别
18:       //printf("p2: %08x, p2[0]: %08x, p2[19]: %08x\n", (int)&p2, (int)&p2[0], (int)&p2[19]);
19:       return 0;
0040105D   xor         eax,eax
20:   }

结果

p和p2虽然都可以理解为指向数组的指针,但还是有细微区别的,它们的内存分别在栈上和堆上
通过上面分析可知,取数组地址时统一使用&p[0] 和 &p2[0] 这种方式是不会出错的。&p和&p2则有可能不是你想要的结果。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-13 21:33:09  更:2022-03-13 21:35:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:40:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码