3
回答
在函数外存取局部变量的一个比喻
注册华为云得mate10,2.9折抢先购!>>>   

在StackOverflow上一这样一个关于C/C++的问题,问问题的人给了一个代码如下:

int * foo()
{
    int a = 5;
    return &a;
}
 
int main()
{
    int* p = foo();
    cout << *p;
    *p = 8;
    cout << *p;
}

你可以编译并运行这个代码(编译时会有一个Warning),结果是:5 8。看上去你可以存取一个函数内的局部变量。但这和我们理解的不一样——函数内的变量在函数退出时就被释放了,不应该在外部还可以被引用。当然,对于 C/C++熟悉的人都知道其实并不是真正的释放,你依然还可以通过内存地址去进行操作,这是C/C++的内存管理的不安全性——指针可以用来乱指。

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

你在某个酒店订了一个房,你入住的时候,你放了一本书在这个酒店的抽屉里,但是你走的时 候,你忘了这本书。而且,你还没有把这个房间的钥匙还回去。于是,你在未来某个时候,偷偷地回来,打开这个房间的门,你看到了你的书还在里间。当然,还还 可以放回别的书。因为,这个酒店管理不会在你走的时候把你留下的书清走,而且,这个酒店的管理的安保措施不是那么严格,因为他信任每一个客人都会遵守管理 条例。

在这种情况下,如果你幸运的话,书还会在那里,也可能你的书已经没了。也有可能当你回去的时候,有一个人在那里正在撕你的书,或者酒店把那个抽屉都挪走并变成衣柜,或是整个酒店正在被拆除以改成了一个足球场,而你偷偷摸摸进到施工现场的时候被炸死。

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

关于这个事,还有一个比较经典的示例如下—— 函数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();
}

真是可爱的C/C++。

转自:http://coolshell.cn/articles/4907.html

举报
华宰
发帖于7年前 3回/166阅
共有3个评论 最后回答: 7年前
我觉得C/C++之所以存在了诸多不安全因素,是因为它把很多系统级别的问题留给程序员自己来解决,这提供了更大的自由度;而有的高级语言的限制太多,也一定程度降低了该语言的灵活度。

      本文不合适.

       0.   关于话题,"在函数外存取局部变量的一个比喻", 几乎只有学了3个月以内的C\C++新手才会讨论这个问题.拿这个问题来分析C\C++毫无意义,因为说明不了任何问题(你的C\C++人生旅程中只有短短的3个月才会这样写, 而学C++ "出山"的周期却长达1~3年,仅是出山). 这个问题只能算是新手的新手问题.(如果你很了解C++,你可以找一些觉得C++技术能力不错的博客,看看3年前博主分析的C++问题,3年后博主分析的C++问题,多分析一些技术博客后,大概就能感性的了解C++的学习周期了.想全面深刻的掌握它,没几年是不可能的.)

       1.  "也正是Linus说的,C++是一门恐怖的语言是因为有很多不合格的程序员在使用它。" 这句话拿来做本文的论据非常不合适.    2个语境,意思完全不同,毫无关系.

       2.  第2个例子, "函数a的初始化会影响函数b的数组" 更是造谣. 例子不具有任何说服力 且和C\C++的 volatile 毫无关系. volatile用于硬件寄存器,或者应对存在外部修改的可能,而这里毫无相关环境.理论上用不用它毫无影响.有影响也是因为编译器的原因,而非C\C++语句产生的效果.

   PS: 可爱一词实在是不能拿来修饰C\C++,它们就像AK47一样一点也不可爱,大概是恐怖分子吧,就算是恐怖分子也应该钟爱人肉炸弹(汇编语言)才对. "可爱","漂亮"应该属于脚本语言.

   拙见,仅供无视.

看不出楼主是什么观点.反正稍微了解一点的人都知道,返回函数内的局部地址(栈地址)是不安全,的,结果未定义,这次可能是5 8 ,下次可能就不是5 8了....

cout<< *p;

cout<< *p;
连续两个输出,第二个就不是5了..

顶部