今天上网看到一个很好玩的也很有深度的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的那一块内存还是可以访问的,但是我们访问的时候理论上来说是非法的,因为这就是相当于野指针是吧,呵呵呵~
我们可以知道:一本书就是a,抽屉就是存放a的内存,钥匙就是说返回a的内存的指针。。。
关于这个事,还有一个比较经典的示例如下——函数a的初始化会影响函数b的数组。注意函数a中的
关键字。
搞定~~~~~~~~
所以C语言真的是很博大精深!所有说C语言简单或者说什么21天学通C/C++都是扯淡不是吗?
引用链接:
http://coolshell.cn/articles/4907.html
#include <iostream>
int * fun()
{
}
int main()
{
}
在编译的时候有一个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
6 for (int i =0; i < 10; i++)
(gdb) s
8 array[i] = i;
(gdb) s
6 for (int i =0; i < 10; i++)
(gdb) p array[i]
$1 = 0
(gdb) s
8 array[i] = i;
(gdb) p array[i]
$2 = 32767
(gdb) s
6 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++都是扯淡不是吗?
引用链接: