0

可能重复:
可以在其范围之外访问局部变量的内存吗?

我认为以下对 f() 的调用将获得指向编译器不会处理的本地内存的指针(根据教科书,这很危险)。但是,它仍然运作良好。不确定这是否安全。

#include <iostream>

using namespace std;

int * f()
{
   int  v[1000000];
   for (int i=0; i<1000000; i++) v[i]=i;
   cout<<v[7]<<endl;
  return  v;
}

int main()
{
   int * v = f();
   cout<<v[7]<<endl;
   return 0;
}
4

5 回答 5

4

有趣的问题。您的代码可能在某些平台上工作(或似乎工作)而在其他平台上失败。

您的代码似乎工作的原因是函数f()在堆栈上保留的内存已释放但在返回时没有被擦除。f()释放后,内存可供其他功能使用;但在另一个函数实际使用它之前,它可能不会被覆盖。

这里的其他一些人正确地指出您的代码会引起未定义的行为,从技术上讲,这是正确的。但是,您得到特定的未定义行为是有原因的,这就是我的答案。

在一些平台上,包括x86,在f()释放内存后v[],第一个被重用的内存通常是之前保存的内存v[999999]。保留的内存可能需要很长时间才能v[0]被重用。因此,来自的数据v[7]仍然虚假地存在。

至少还有一个皱纹。一些实现,使用一些设置,可能会立即用随机数据覆盖所有释放的内存,以防范安全风险。(例如,如果v[]持有密码怎么办?随机数据会安全地将其擦除。)

于 2012-04-27T15:35:27.947 回答
4

vin的指针main()是返回后的悬空指针f()。取消引用悬空指针是未定义的行为,这意味着任何事情都可能发生:

  • 它可能会崩溃
  • 它可能会打印不正确的整数值
  • 它可以打印正确的整数值
于 2012-04-27T15:31:53.310 回答
4

因为它是未定义的行为,而未定义的行为并不一定意味着崩溃。
这当然是不安全的。
未定义的行为意味着所有安全赌注都已关闭,实际上任何事情都可能发生,所以如果它没有崩溃并不意味着它是有效的。这是无效的,你不应该这样做!

于 2012-04-27T15:31:53.653 回答
1

未定义的行为:它可以工作,或者崩溃,或者擦除你的硬盘,或者内爆到一个黑洞,或者和你的妻子一起逃跑。

不过有一件事是肯定的:它会导致你的课程不及格。

于 2012-04-27T15:34:21.220 回答
1

如其他答案所述,这是未定义的行为,因此您不能依赖它正常工作。它可能在某些平台或某些编译器上工作正常,但在其他编译器上则不行。你'侥幸逃脱'主要是因为你的程序小而简单。您对程序的详细说明越多,您遇到问题的可能性就越大。

于 2012-04-27T15:40:34.310 回答