我有下面的代码。

#include <iostream>

int * foo()
{
    int a = 5;
    return &a;
}

int main()
{
    int* p = foo();
    std::cout << *p;
    *p = 8;
    std::cout << *p;
}

并且代码正在运行,没有运行时异常!

输出是58

怎么可能呢?局部变量的内存在其函数之外不是不可访问的吗?


当前回答

如果使用::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在返回地址后被销毁。您可以通过返回的地址访问修改后的值。

让我举一个真实的例子:

假设一个人把钱藏在一个地方,并告诉你这个地方。过了一段时间,告诉你钱的位置的人死了。但你仍然可以拿到那些隐藏的钱。

因为存储空间还没有被践踏。不要指望那种行为。

It's 'Dirty' way of using memory addresses. When you return an address (pointer) you don't know whether it belongs to local scope of a function. It's just an address. Now that you invoked the 'foo' function, that address (memory location) of 'a' was already allocated there in the (safely, for now at least) addressable memory of your application (process). After the 'foo' function returned, the address of 'a' can be considered 'dirty' but it's there, not cleaned up, nor disturbed/modified by expressions in other part of program (in this specific case at least). A C/C++ compiler doesn't stop you from such 'dirty' access (might warn you though, if you care). You can safely use (update) any memory location that is in the data segment of your program instance (process) unless you protect the address by some means.

正如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”,但您的结果可能会有所不同(真的!)你的指针正在敲打其他不相关的局部变量。

给所有的答案补充一点:

如果你这样做:

#include<stdio.h>
#include <stdlib.h>
int * foo(){
    int a = 5;
    return &a;
}
void boo(){
    int a = 7;

}
int main(){
    int * p = foo();
    boo();
    printf("%d\n",*p);
}

输出可能是:7

这是因为从foo()返回后,堆栈被释放,然后被boo()重用。 如果你分解可执行文件,你会清楚地看到它。