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

时间:2018-03-22 08:53:55

标签: c++ pointers

我刚刚开始学习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的参数?我真的很困惑。如果这是一个非常基本的问题,我也很抱歉。

2 个答案:

答案 0 :(得分:7)

这条指令:

int* p = &n;

指定一个指向本地自动变量n的指针。

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

 return p;

指针变为无效。将其存储在nn并使用带有*nn的解除引用值来触发未定义的行为 - 您无法知道之后会发生什么。

在您的特定情况下实际发生的事情(归功于@Caleth)可能是n变量存储在机器堆栈上,然后{{{}}使用相同的位置{ {1}}的{​​1}},因此会被参数的na值覆盖到f2()

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

P.S。
在C中也是如此,而不仅仅是在C ++中。使用f2及其na运算符与问题无关。

答案 1 :(得分:0)

作为CiaPan notes in his/her answer,只要返回指向局部变量的指针,就处于未定义的行为区域。下面是实际发生的事情:你的局部变量存储在函数调用堆栈中,它在每个函数调用/返回时改变状态。当函数返回时,它通常不会清除它使用的堆栈内存,因此它可能看起来仍然有效。但是根据语言标准,该内存几乎不存在,任何指向它的指针都会立即失效。我希望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 |
           \         ^    
            \________/
相关问题