一亩三分地论坛

 找回密码
 获取更多干货,去instant注册!

扫码关注一亩三分地公众号
查看: 1575|回复: 21
收起左侧

[学C/C++] C++关于指针和地址的一个小问题

[复制链接] |试试Instant~ |关注本帖
ykay25 发表于 2016-5-12 23:07:12 | 显示全部楼层 |阅读模式

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看,没有帐号?获取更多干货,去instant注册!

x
本帖最后由 ykay25 于 2016-5-12 23:10 编辑

欲设计一程序,int i=1之后,找出i的地址(为0x20c7fe68),创建int*类型的b指针指向该地址0x20c7fe68,并将2赋值给*b,从而i的值也变为2。


以下两则程序仅差一行输出语句,但输出结果完全不同,请问大神们可否赐教是什么原因?


程序A
  1. using namespace std;

  2. int main() {
  3.     int i = 1;
  4.     int *b = (int*)0x20c7fe68;
  5.     cout << "*b = " << *b << endl;
  6.     cout << "&i = " << &i << endl;
  7.     *b = 2;
  8.     cout << "i = " << i << endl;
  9.     return 0;
  10. }
复制代码


Console的输出为:(i = 2,成功)
  1. *b = 1
  2. &i = 0x20c7fe68
  3. i = 2
复制代码


程序B
  1. using namespace std;

  2. int main() {
  3.     int i = 1;
  4.     int *b = (int*)0x20c7fe68;
  5.     cout << "*b = " << *b << endl;
  6.     *b = 2;
  7.     cout << "i = " << i << endl;
  8.     return 0;
  9. }
复制代码


Console的输出为:(i = 1,失败)
  1. *b = 549977704
  2. i = 1
复制代码


两者相差的语句仅为
  1. cout << "&i = " << &i << endl;
复制代码











补充内容 (2016-5-14 09:44):
已解决,引用pbj十二楼:“因为第二段代码的i根本是没用的变量 被编译器直接优化了 所以i根本没有分配到任何地址。第一段代码你取i的地址了 编译器给他分配了地址。”
luochen01 发表于 2016-5-12 23:30:10 | 显示全部楼层
本帖最后由 luochen01 于 2016-5-12 23:34 编辑

变量i的地址每次不一样的吧。。
回复 支持 反对

使用道具 举报

zengqlleo 发表于 2016-5-13 10:22:13 | 显示全部楼层
你确定你每次运行程序A都能得到i=2?
回复 支持 反对

使用道具 举报

mynn2003 发表于 2016-5-13 10:52:34 | 显示全部楼层
i是在栈里的,程序一变就都变了。地址不可能永远固定不变,不要再这么使用了
回复 支持 反对

使用道具 举报

Augustus 发表于 2016-5-13 11:03:34 | 显示全部楼层
迷之代码。。。长这么大第一次见,如果面试的时候用了一定onsite妥妥的。。。
回复 支持 反对

使用道具 举报

 楼主| ykay25 发表于 2016-5-13 19:54:48 | 显示全部楼层
zengqlleo 发表于 2016-5-13 10:22
你确定你每次运行程序A都能得到i=2?

是的。。。每次运行完其他程序重开编译器再来运行这个,或者是关机再开机再运行,结果都是一样的。。。
回复 支持 反对

使用道具 举报

 楼主| ykay25 发表于 2016-5-13 19:55:03 | 显示全部楼层
luochen01 发表于 2016-5-12 23:30
变量i的地址每次不一样的吧。。

每次运行完其他程序重开编译器再来运行这个,或者是关机再开机再运行,结果都是一样的。。。变量i的地址也都是一样的。。。
回复 支持 反对

使用道具 举报

 楼主| ykay25 发表于 2016-5-13 19:55:30 | 显示全部楼层
Augustus 发表于 2016-5-13 11:03
迷之代码。。。长这么大第一次见,如果面试的时候用了一定onsite妥妥的。。。

求不吐槽
回复 支持 反对

使用道具 举报

luochen01 发表于 2016-5-13 21:36:15 | 显示全部楼层
本帖最后由 luochen01 于 2016-5-13 22:51 编辑
ykay25 发表于 2016-5-13 19:55
每次运行完其他程序重开编译器再来运行这个,或者是关机再开机再运行,结果都是一样的。。。变量i的地址 ...

回复 支持 反对

使用道具 举报

bestcql 发表于 2016-5-13 21:51:00 | 显示全部楼层
如果楼主还没有解决问题的话,可以去segmentfault问问,应该会得到满意的解答
回复 支持 反对

使用道具 举报

bestcql 发表于 2016-5-13 21:54:05 | 显示全部楼层
觉得第二次的地址应该跟第一次不一样了,所以int *b =  &i ,第二段中,i的地址不一定再是0x20c7fe68应该就没问题了
回复 支持 反对

使用道具 举报

pbj 发表于 2016-5-13 22:42:13 | 显示全部楼层
因为第二段代码的i根本是没用的变量 被编译器直接优化了 所以i根本没有分配到任何地址。
第一段代码你取i的地址了 编译器给他分配了地址。

你可以给i定义的时候加volatile 我猜即使没有  cout << "i = " << i << endl; 也能获得和第一段一样的结果。
回复 支持 反对

使用道具 举报

 楼主| ykay25 发表于 2016-5-14 09:43:05 | 显示全部楼层
pbj 发表于 2016-5-13 22:42
因为第二段代码的i根本是没用的变量 被编译器直接优化了 所以i根本没有分配到任何地址。
第一段代码你取i ...

volatile试过了,你是正解!!大师啊
回复 支持 反对

使用道具 举报

zengqlleo 发表于 2016-5-16 10:36:47 | 显示全部楼层
pbj 发表于 2016-5-13 08:42
因为第二段代码的i根本是没用的变量 被编译器直接优化了 所以i根本没有分配到任何地址。
第一段代码你取i ...

难道C的编译器会自动把变量放在已声明的指针里?否则每次都在固定地址说不通啊。。。。
回复 支持 反对

使用道具 举报

pbj 发表于 2016-5-16 21:49:29 | 显示全部楼层
zengqlleo 发表于 2016-5-15 21:36
难道C的编译器会自动把变量放在已声明的指针里?否则每次都在固定地址说不通啊。。。。

其实我也不是很明白 为什么每次都能是固定地址 但我猜跟编译环境的设置有关系 不过想想局部变量是放在栈里的 而你的i每次都是栈中定义的第一个变量 这个地址是你当前环境的栈底地址 感觉也应该能说的通。

这应该和编译原理有关系 没有学过相关的东西 只是瞎猜。
回复 支持 反对

使用道具 举报

sheepmiemies 发表于 2016-5-17 01:10:59 | 显示全部楼层
好神奇,借楼问几个问题:

1. 好奇是什么样的环境,在每次运行的时候分配的地址居然都是一样的。。。我自己写就两行函数,每次得到的地址是不一样的额
  1. int i = 1;
  2. cout << &i << endl;
复制代码


2. 怎么定义一个变量是无用变量呢?因为原代码好歹 i 是用来输出了。

3. 为什么要固定使用一个地址?
回复 支持 反对

使用道具 举报

stellari 发表于 2016-5-17 06:06:40 | 显示全部楼层
sheepmiemies 发表于 2016-5-17 01:10
好神奇,借楼问几个问题:

1. 好奇是什么样的环境,在每次运行的时候分配的地址居然都是一样的。。。我 ...

1. 至少windows下的g++是这样。我在win10和MinGW gcc/g++环境下,可以完全复现楼主描述的现象。但是改用Visual Studio 2012的话,就无法得到每次完全一样的地址(每次的地址差不太多但不完全一样)。

至于相同的原因,可能是因为这里打印的地址是Virtual Address,并非实际的Physical Address。所以如果程序每次创建本进程内存空间的过程完全相同,且栈顶指针初始化位置相同,那么栈中第一个元素地址保持不变也是合理的。

2. 判定的依据是“as-if”规则,也就是只要不改变程序的“由C++标准规定的可见行为”,编译器就可自行决定删除,重构某些代码。楼主的代码B里,i只有一个作用,就是用来输出一个1。那么当编译器发现i的值从始至终就没有改变过,那么它完全可以不定义i,而是直接输出一个常数1. 但是,声明为volatile以后,编译器就不能对i做同样的假设,因为i的值随时可能会受到其他代码的影响。同样,当引用了“& i ”时,那么编译器就不得不为i实际分配地址,来满足 & 运算符的需要。

回复 支持 反对

使用道具 举报

sheepmiemies 发表于 2016-5-17 06:24:49 | 显示全部楼层
stellari 发表于 2016-5-17 06:06
1. 至少windows下的g++是这样。我在win10和MinGW gcc/g++环境下,可以完全复现楼主描述的现象。但是改用V ...

比较懒就自己试了下visual studio,哈哈!原来有这么一个规则,多谢解释!
回复 支持 反对

使用道具 举报

stellari 发表于 2016-5-17 06:34:29 | 显示全部楼层
sheepmiemies 发表于 2016-5-17 06:24
比较懒就自己试了下visual studio,哈哈!原来有这么一个规则,多谢解释!

其实我现在反而想知道的是,Visual Studio到底做了什么,使得每次给进程分配的Virtual Space的栈顶的位置不同的呢?
回复 支持 反对

使用道具 举报

 楼主| ykay25 发表于 2016-5-17 11:36:17 | 显示全部楼层
stellari 发表于 2016-5-17 06:06
1. 至少windows下的g++是这样。我在win10和MinGW gcc/g++环境下,可以完全复现楼主描述的现象。但是改用V ...

第2点解释得妙。。。原来是因为i在编译器里没有被定义。

我和你的测试结果一样,用Visual Studio 2012的话就无法得到完全一样的地址,而我自己用的编译器是Qt Creator,每次地址一样。
回复 支持 反对

使用道具 举报

本版积分规则

请点这里访问我们的新网站:一亩三分地Instant.

Instant搜索更强大,不扣积分,内容组织的更好更整洁!目前仍在beta版本,努力完善中!反馈请点这里

关闭

一亩三分地推荐上一条 /5 下一条

手机版|小黑屋|一亩三分地论坛声明 ( 沪ICP备11015994号 )

custom counter

GMT+8, 2016-12-11 03:18

Powered by Discuz! X3

© 2001-2013 Comsenz Inc. Design By HUXTeam

快速回复 返回顶部 返回列表