通过汇编理解返回char p []和char *p 中P的区别
来源:互联网 发布:dota2 mac 国服下载 编辑:程序博客网 时间:2024/06/05 13:30
用两个程序帮助理解返回char p []和char *p 中p的区别。
第一个程序test01.cpp的源代码:
/* *filename:test01.cpp */#include <stdio.h> char *returnStr(){char *p = "hello world!";return p;}int main(){char *str;str = returnStr();printf("%s\n", str);return 0;}
test001.cpp的运行结果:hello world!
第二个程序test002.cpp的源代码
/* *filename:test02.cpp */#include <stdio.h> char *returnStr(){char p[] = "hello world!";return p;}int main(){char *str;str = returnStr();printf("%s\n", str);return 0;}
返回的结果是乱码的:烫烫烫烫烫烫烫烫,
两个程序代码上的区别在于:
test01.cpp的是
char *p = "hello world!";
test02.cpp的是:
char p[] = "hello world!";
网上解释的是:
test01.cpp程序返回的是指向常量区的地址。程序返回后,常量区地址的内容未变,所以能正常返回“hello world!”
test02.cpp程序返回的是指向的是栈空间的地址,函数返回后,栈空间被释放,返回的地址所指的内容不确定,所以会出现此问题。
以上的解释是能和结果吻合的,但是心中还是有个疑问,等号右边都是一样的“hell world!”,为什么char *p中的p为常量区的地址,而char p[ ]中的p为栈区的地址。于是vs 弄起,看下看下两个程序的关键部分的汇编(前不久自学的汇编,菜鸟一个)。
先看下test02.cpp部分代码的汇编。
char p[] = "hello world!";return p;上面两行代码通过vs反汇编看到的汇编代码:
7: char p[] = "hello world!";00073D88 A1 30 6B 07 00 mov eax,dword ptr ds:[00076B30h] 00073D8D 89 45 E8 mov dword ptr [ebp-18h],eax 00073D90 8B 0D 34 6B 07 00 mov ecx,dword ptr ds:[00076B34h] 00073D96 89 4D EC mov dword ptr [ebp-14h],ecx 00073D99 8B 15 38 6B 07 00 mov edx,dword ptr ds:[00076B38h] 00073D9F 89 55 F0 mov dword ptr [ebp-10h],edx 00073DA2 A0 3C 6B 07 00 mov al,byte ptr ds:[00076B3Ch] 00073DA7 88 45 F4 mov byte ptr [ebp-0Ch],al 8: return p;00073DAA 8D 45 E8 lea eax,[ebp-18h] 9: }从上面看可知,编译器把ds:[00076B30h](备注:可通过vs查看到此时ds寄存器的值为0)的13个字节(加上最后的‘‘\0’)先通过复制到寄存器(一共分4次复制,因为eax、ecx、edx均为4个字节大小,最后一个al为1个字节大小),然后再把寄存器的值复到[ebp-18h](可通过vs查看到此时EBP = 0055F998)地址开始的栈空间(从[ebp-18h]到[ebp-0Ch] 正好是13个字节的空间)。
我们可以看下ds:[00076B30h]内存地址开始的内容:
再看下[ebp-18h]内存地址的空间:
从上面的内容可以看出,同样是“helloword”字符串,他们的地址是不一样的。也就是说,下面这段代码:
char p[] = "hello world!";return p;编译器会重新开辟一个栈空间,把数据的段的“hello world!”复制到栈空间,然后再把这段内容的栈空间的起始地址返回。
再看下test01.cpp关键代码:
char *p = "hello world!";return p;
其对应的汇编
7: char *p = "hello world!";00DB170E C7 45 F8 30 6B DB 00 mov dword ptr [ebp-8],0DB6B30h 8: return p;00DB1715 8B 45 F8 mov eax,dword ptr [ebp-8] 9: }0DB6B30h就是存储“hello world!”的数据段起始地址。
也就是说把数据段的地址复制到一个16字节的内存空间(虽然也是栈空间,因为指针变量p占用的是栈空间),再把这段栈空间的值(其实就是数据段地址)复制给eax。没有重新开辟13个栈空间去存储“hello world!”字符串,只是存储地址而已。所以返回的直接就是常量区“hello world!”的地址。
总结:
char *p = "hello world!";return p;以上的第一行代码不会重新开辟栈空间去存储字符串"hello world!",开辟的栈空间是为了存储常量区"hello world!"的起始地址,返回的也是常量区"hello world!"的起始地址p。
char p[] = "hello world!";return p;
以上的第一行代码会开辟栈空间去存储字符串"hello world!",返回的是在栈中存储这段字符串的起始地址,即返回的栈空间的地址p。
- 通过汇编理解返回char p []和char *p 中P的区别
- char *p和 char p[]的区别
- char *p和 char p[]的区别?
- char* p 和 char p[] 的区别
- char *p 与 char p[]的区别
- 5分钟理解不遗忘const char *p,char *const p和const char *const p的区别
- 关于指针char *p和数组char p[] 的区别
- char *p和char p[]的问题
- char*p 和 char p[]
- char* p 和char p[]
- char *p 和char *p[]
- char* p和char p[];
- char *p[5] 和 char p[5][10] 和 char **p的区别
- c中有关char *p 和char a[6] ,char a[] char a[0] 的区别
- 理解一下char**p char*p[]
- 解析char *p与char p[] 区别
- char *p 与char p[]区别,strcpy_s
- char *p 与 extern char*p区别
- NetworkX之Prim算法
- 训练集、验证集与测试集回顾总结
- meta 和 微信内置浏览器
- Ajax客户端异步调用服务端方法(js调用cs文件)
- 关于文件过滤器的小代码
- 通过汇编理解返回char p []和char *p 中P的区别
- 人工智能的理解
- 程序员必备:一款知识管理利器+效率工具
- LeetCode week 16 : Insert Interval
- pandoc——文档转换神器
- Apache2.4.48-Mysql5.7.20-PHP7.1.12超详细图文配置教程
- 句柄泄露与CloseHandle
- 20171217---Day015
- Jquery使用ajax提交文件