我有下面的代码。

#include <iostream>

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

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

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

输出是58

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


当前回答

你的代码风险很大。你正在创建一个局部变量(在函数结束后被认为是被销毁的),并且在该变量被销毁后返回该变量的内存地址。

这意味着内存地址可能是有效的,也可能是无效的,您的代码将容易受到可能的内存地址问题的影响(例如分割错误)。

这意味着你正在做一件非常糟糕的事情,因为你正在把一个内存地址传递给一个根本不可信的指针。

考虑这个例子,并测试它:

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的内存分配到本地函数中 当函数过期时,该内存地址仍然有效(它不会被任何人删除)。 内存地址是可信任的(该内存块不被认为是空闲的,因此在删除它之前不会被覆盖) 内存地址不使用时应删除。(见程序末尾的删除)

其他回答

正如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
}

在c++中,你可以访问任何地址,但这并不意味着你应该这样做。您正在访问的地址不再有效。它之所以能工作,是因为在foo返回后没有其他东西扰乱内存,但在许多情况下它可能崩溃。试着用Valgrind分析你的程序,甚至只是优化编译它,然后看看…

这是典型的未定义行为,两天前在这里讨论过——搜索一下网站。简而言之,您是幸运的,但是任何事情都可能发生,并且您的代码正在对内存进行无效的访问。

你的代码风险很大。你正在创建一个局部变量(在函数结束后被认为是被销毁的),并且在该变量被销毁后返回该变量的内存地址。

这意味着内存地址可能是有效的,也可能是无效的,您的代码将容易受到可能的内存地址问题的影响(例如分割错误)。

这意味着你正在做一件非常糟糕的事情,因为你正在把一个内存地址传递给一个根本不可信的指针。

考虑这个例子,并测试它:

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的内存分配到本地函数中 当函数过期时,该内存地址仍然有效(它不会被任何人删除)。 内存地址是可信任的(该内存块不被认为是空闲的,因此在删除它之前不会被覆盖) 内存地址不使用时应删除。(见程序末尾的删除)