指针被分配给错误的局部变量

Pointer is assigned to wrong local variable

本文关键字:局部变量 错误 分配 指针      更新时间:2023-10-16

我刚刚开始学习 c++,我这里有一些示例代码,显示了局部变量和指针的问题。

#include <iostream>
using namespace std;
int* f1 (int n) {
int* p = &n;
return p;
}//f1
void f2 (int na) {
int nb = na;
}//f2
int main () {
int* nn = f1 (101);
f2 (2002);
cout << *nn << endl;
}//main
/* 
2002 // output MinGW 6.2.0
*/

不幸的是,我找不到为什么会发生这种情况的解释。据我了解,p 返回给调用方,所以 nn 应该等于 101,但它以某种方式分配给了赋予 f2 的参数?我真的很困惑。如果这是一个非常基本的问题,我也很抱歉。

此指令:

int* p = &n;

将指针分配给局部自动变量n

该变量在f1()结束时被销毁,因此一旦您执行

return p;

指针变为无效。将其存储在nn中并通过取消引用来使用指向值*nn触发未定义的行为- 您无法知道之后会发生什么。

在您的特定情况下实际发生的情况(归功于 @Caleth)可能是n变量存储在机器堆栈上,然后naf2()使用相同的位置,因此它被要f2的参数的2002值覆盖。

永远不要依赖这样的效果!变量不需要以相同的方式分配给不同的函数,例如,堆栈帧可以逐个堆叠,并在以后释放几个后续调用(我在 - IIRC - Watcom C 编译器中见过这样的行为很多年前),或者na可以在微处理器的寄存器中分配。无论如何,即使它们位于堆栈上并且位于堆栈的同一位置,它们也不需要保持相同的值!该堆栈可以由其他机制使用,不一定在源代码中可见。

附言:
同样的情况发生在C语言中,而不仅仅是在C++中。将cout与其<<运算符一起使用在问题中并不重要。

正如 CiaPan 在他/她的回答中指出的那样,一旦你返回指向局部变量的指针,你就处于未定义的行为领域。以下是幕后实际发生的情况:您的局部变量存储在函数调用堆栈中,该堆栈在每次函数调用/返回时都会更改状态。当函数返回时,它通常不会清除它使用的堆栈内存,因此它可能看起来仍然有效。但按照语言标准,这种记忆几乎不复存在,任何指向它的指针都会立即失效。我希望ASCII艺术能帮助你理解到底发生了什么。

Before call of f1():
| main(): nn |
| ?????????? |
|
v
???
During execution of f1():
| main(): nn | f1(): n  | f1(): p  |
| ?????????? |      101 |       &n |
|         ^          /
v          ________/
???
After f1() returns (nn is invalid as n does not exist anymore):
| main(): nn | unused space        |
|    invalid |      101 |       &n |
         ^    
________/
During execution of f2() (nn is still invalid, but seems to point to na now):
| main(): nn | f2(): na | f2(): nb |
|    invalid |     2002 |     2002 |
         ^    
________/
After f2() returns, nn is still invalid, but points to the memory that was once occupied by na:
| main(): nn | unused space        |
|    invalid |     2002 |     2002 |
         ^    
________/