我有下面的代码。
#include <iostream>
int * foo()
{
int a = 5;
return &a;
}
int main()
{
int* p = foo();
std::cout << *p;
*p = 8;
std::cout << *p;
}
并且代码正在运行,没有运行时异常!
输出是58
怎么可能呢?局部变量的内存在其函数之外不是不可访问的吗?
我有下面的代码。
#include <iostream>
int * foo()
{
int a = 5;
return &a;
}
int main()
{
int* p = foo();
std::cout << *p;
*p = 8;
std::cout << *p;
}
并且代码正在运行,没有运行时异常!
输出是58
怎么可能呢?局部变量的内存在其函数之外不是不可访问的吗?
当前回答
你的问题与范围无关。在你所展示的代码中,函数main看不到函数foo中的名称,所以你不能在foo之外直接使用这个名称访问foo中的a。
您遇到的问题是为什么程序在引用非法内存时不发出错误信号。这是因为c++标准在非法内存和合法内存之间没有明确的界限。引用弹出堆栈中的内容有时会导致错误,有时不会。视情况而定。不要指望这种行为。假设在编程时它总是会导致错误,但在调试时它永远不会发出错误信号。
其他回答
你的问题与范围无关。在你所展示的代码中,函数main看不到函数foo中的名称,所以你不能在foo之外直接使用这个名称访问foo中的a。
您遇到的问题是为什么程序在引用非法内存时不发出错误信号。这是因为c++标准在非法内存和合法内存之间没有明确的界限。引用弹出堆栈中的内容有时会导致错误,有时不会。视情况而定。不要指望这种行为。假设在编程时它总是会导致错误,但在调试时它永远不会发出错误信号。
正如Alex指出的那样,这种行为是未定义的——事实上,大多数编译器都会警告不要这样做,因为这很容易导致崩溃。
对于你可能遇到的令人毛骨悚然的行为,可以试试这个例子:
int *a()
{
int x = 5;
return &x;
}
void b( int *c )
{
int y = 29;
*c = 123;
cout << "y=" << y << endl;
}
int main()
{
b( a() );
return 0;
}
这将输出“y=123”,但您的结果可能会有所不同(真的!)你的指针正在敲打其他不相关的局部变量。
因为存储空间还没有被践踏。不要指望那种行为。
你只是返回一个内存地址,这是允许的,但可能是一个错误。
是的,如果你试图解引用该内存地址,你将有未定义的行为。
int * ref () {
int tmp = 100;
return &tmp;
}
int main () {
int * a = ref();
//Up until this point there is defined results
//You can even print the address returned
// but yes probably a bug
cout << *a << endl;//Undefined results
}
你的代码风险很大。你正在创建一个局部变量(在函数结束后被认为是被销毁的),并且在该变量被销毁后返回该变量的内存地址。
这意味着内存地址可能是有效的,也可能是无效的,您的代码将容易受到可能的内存地址问题的影响(例如分割错误)。
这意味着你正在做一件非常糟糕的事情,因为你正在把一个内存地址传递给一个根本不可信的指针。
考虑这个例子,并测试它:
int * foo()
{
int *x = new int;
*x = 5;
return x;
}
int main()
{
int* p = foo();
std::cout << *p << "\n"; //better to put a new-line in the output, IMO
*p = 8;
std::cout << *p;
delete p;
return 0;
}
不像你的例子,在这个例子中你是:
将int的内存分配到本地函数中 当函数过期时,该内存地址仍然有效(它不会被任何人删除)。 内存地址是可信任的(该内存块不被认为是空闲的,因此在删除它之前不会被覆盖) 内存地址不使用时应删除。(见程序末尾的删除)