我有下面的代码。
#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
怎么可能呢?局部变量的内存在其函数之外不是不可访问的吗?
当前回答
它之所以能工作,是因为自从a被放入堆栈以来,堆栈(还没有)被改变过。 在再次访问a之前调用一些其他函数(它们也调用其他函数),你可能不会再那么幸运了……: -)
其他回答
你只是返回一个内存地址,这是允许的,但可能是一个错误。
是的,如果你试图解引用该内存地址,你将有未定义的行为。
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
}
如果使用::printf而不使用cout,控制台输出的内容可能会发生巨大变化。 你可以在以下代码中使用调试器(在x86, 32位,MSVisual Studio上测试):
char* foo()
{
char buf[10];
::strcpy(buf, "TEST”);
return buf;
}
int main()
{
char* s = foo(); //place breakpoint & check 's' varialbe here
::printf("%s\n", s);
}
从函数返回后,所有标识符都将被销毁,而不是将值保存在内存位置,如果没有标识符,则无法定位值。但该位置仍然包含前一个函数存储的值。
因此,这里函数foo()返回a的地址,a在返回地址后被销毁。您可以通过返回的地址访问修改后的值。
让我举一个真实的例子:
假设一个人把钱藏在一个地方,并告诉你这个地方。过了一段时间,告诉你钱的位置的人死了。但你仍然可以拿到那些隐藏的钱。
这是典型的未定义行为,两天前在这里讨论过——搜索一下网站。简而言之,您是幸运的,但是任何事情都可能发生,并且您的代码正在对内存进行无效的访问。
正如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”,但您的结果可能会有所不同(真的!)你的指针正在敲打其他不相关的局部变量。