关于C/C++: 在函数外存取局部变量问题( 精辟 )

今天上网看到一个很好玩的也很有深度的C++问题,代码是这样的:
 
           
#include <iostream>

int * fun()
{
      int a =5;
      return (&a);      //!> 注意一般我们不会这样做的,这是没有意义而且是危险的
                                                  //!> 如果想不通,来看看下面吧
 
int main()
{
      int * p =fun();
      std::cout<< *p;
      *p =8;
      std::cout<< *p;
      return  0;
}

在编译的时候有一个warning:
test.cpp: In function ‘int* fun()’:
test.cpp:7: warning: address of local variable ‘a’ returned

大家可以很快的回答出来答案是5 8对吧~但是你的理解对了吗?看下面~
最终的结果在VC++下,在g++下运行都是C. 58:-)~,下面我们来看看C++内部的实质~
附加:我在GDB调试下的结果:
(gdb) file test
Reading symbols from /home/pt/桌面/test/test...done.
(gdb) r
Starting program: /home/pt/桌面/test/test
58
Program exited normally.

如果你认为是你还是应用了a这个变量,那么你就是大错特错了。熟悉C++的都知道,只要是函数退出了那么局部变量肯定在函数返回之前就释放了,这是必需的,但是我们知道,那个之前保存a的那一块内存还是可以访问的,但是我们访问的时候理论上来说是非法的,因为这就是相当于野指针是吧,呵呵呵~

这个问题的解答是比较简单的,但是这个问题有一个答案中的比喻非常精彩。这个比喻是这样的——

你在某个酒店订了一个房,你入住的时候,你放了一本书在这个酒店的抽屉里,但是你走的时候,你忘了这本书。而且,你还没有把这个房间的钥匙还回去。于是,你在未来某个时候,偷偷地回来,打开这个房间的门,你看到了你的书还在里间。当然,还还可以放回别的书。因为,这个酒店管理不会在你走的时候把你留下的书清走,而且,这个酒店的管理的安保措施不是那么严格,因为他信任每一个客人都会遵守管理条例。在这种情况下,如果你幸运的话,书还会在那里,也可能你的书已经没了。也有可能当你回去的时候,有一个人在那里正在撕你的书,或者酒店把那个抽屉都挪走并变成衣柜,或是整个酒店正在被拆除以改成了一个足球场,而你偷偷摸摸进到施工现场的时候被炸死。

真是很精彩的比喻。这就是C/C++的不安全的地方,也正是Linus说的, C++是一门恐怖的语言是因为有很多不合格的程序员在使用它。就像你看到小孩子玩火一样的恐怖。

我们可以知道:一本书就是a,抽屉就是存放a的内存,钥匙就是说返回a的内存的指针。。。

关于这个事,还有一个比较经典的示例如下——函数a的初始化会影响函数b的数组。注意函数a中的  volatile
关键字。


#include<iostream>
using namespace std; 
void a()
{
     volatile int array[10];
     for ( int i = 0; i< 10; i++)
   {
         array[i]= i;
   }
}
 
void b()
{
     int array[10];
     for ( int i = 0; i< 10; i++)
   {
       
cout <<array[i];
   }
}
 
int main()
{
     a();
     b();
}

结果是:0123456789,你猜到了吗?:-)~
看一下GDB单步调试:
(gdb) b a
Breakpoint 1 at 0x400788: file t2.cpp, line 6.
(gdb) b b
Breakpoint 2 at 0x4007b6: file t2.cpp, line 15.
(gdb) r
Starting program: /home/pt/桌面/test/t

Breakpoint 1, a () at t2.cpp:6
      for (int i =0; i < 10; i++)
(gdb) s
         array[i] = i;
(gdb) s
      for (int i =0; i < 10; i++)
(gdb) p array[i]
$1 = 0
(gdb) s
         array[i] = i;
(gdb) p array[i]
$2 = 32767
(gdb) s
      for (int i =0; i < 10; i++)
(gdb) p array[i]
$3 = 1
(gdb) d 1
(gdb) c
Continuing.

Breakpoint 2, b () at t2.cpp:15
15       for (int i =0; i < 10; i++)
(gdb) p array[i]
$4 =4196000                    //!> 这是b中初始化时候的array时候的随机值,是OK的
(gdb) s
17          cout << array[i];
(gdb) s
15       for (int i =0; i < 10; i++)
(gdb) p array[i]
$5 =0                          //!> 看到这一步真的奇怪,为什么就是a中的正常的数呢???
(gdb) s
17          cout << array[i];
(gdb) p array[i]
$6 =1                          //!> 还有这个,下面就不贴了

这是为什么呢?看看
volatile关键字吧,

可能很多人都没有用过这个关键字,这个意思就是说:
volatile告诉编译器数组是随时可能发生变化的,每次使用它的时候必须从最初的数组array的地址中读取,因而编译器生成的可执行码会重新从原始的数组array的地址读取数据。

搞定~~~~~~~~

所以C语言真的是很博大精深!所有说C语言简单或者说什么21天学通C/C++都是扯淡不是吗?

引用链接:  http://coolshell.cn/articles/4907.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值