为什么返回指向局部变量或参数的指针是不好的做法?

我在学习指南中发现了这个问题,我不确定为什么返回指向局部变量/参数的指针会很糟糕。 有任何想法吗?

这不是一个“坏习惯”(暗示它可能会导致问题),而是一种绝对会导致未定义行为的做法。 这就像解除引用空指针一样:不要这样做并期望程序在逻辑限制内运行。

说明:

当声明局部变量(包括参数)时,它被赋予自动存储 ,这意味着编译器负责为变量分配内存,然后在程序员的帮助下解除分配该内存。

void foo(int bar) { int baz; } //baz and bar dissappear here 

当变量’lifetime终止时(例如函数返回时),编译器将履行其承诺,并且销毁函数本地的所有自动变量。 这意味着任何指向这些变量的指针现在指向程序认为“免费”执行任何操作的垃圾内存。

返回值时,这不是问题:程序找到一个新位置来放置值。

 int foo(int bar) { int baz = 6; return baz + bar; //baz + bar copied to new memory location outside of foo } //baz and bar disapear 

返回指针时,指针的值将照常复制。 但是, 指针仍指向同一位置,现在是垃圾

 int* foo(int bar) { int baz = 6; baz += bar; return &baz; //(&baz) copied to new memory location outside of foo } //baz and bar disapear! &baz is now garbage memory! 

访问此内存是不明确的行为,因此您的程序几乎肯定会以某种方式行为不端。 例如,我曾经成为这个确切问题的受害者 ,虽然我的程序没有崩溃或终止,但我的变量开始降级为垃圾值,因为编译器覆盖了“免费”内存。

因为它在程序中导致未定义的行为。

如果在函数返回后返回指向局部变量的指针,则它超出范围。 从那时起,如果您访问返回的指针,则它是未定义的行为。

函数返回后,堆栈中的局部变量和参数已被解除分配。 它们可能仍然存在,但是没有任何保证,当某些东西决定使用堆栈时,它们肯定会受到打击。

使用WP中的图表:

堆栈图

顶部的堆栈指针是可以安全地分配和放置新变量的位置(例如调用函数时)。 当函数(例如DrawLine)返回时,它们将从堆栈中取出(堆栈指针只是递增,因此它不再指向超出范围的绿色变量)。 稍后出现并分配和使用堆栈空间的任何内容都将破坏旧值。

局部变量存储在堆栈中。 存储在堆栈中的值会在函数/代码块退出时被销毁(即,您到达函数的末尾 – 从技术上讲,它们可以持续更长时间,但这是另一个讨论)。 因此,指针(指向存储器中特定位置的地址)指向可能不再存在的值。

因为该变量的地址属于创建它的堆栈帧。 没有其他的。 return ,该激活记录将被清除,之前存在的任何内容现在都未定义。