【发布时间】:2020-06-04 23:35:12
【问题描述】:
所以我搞砸了动态内存和指针,我想知道当涉及到指向局部变量的指针时,C 是如何管理堆栈的。 我想出了这个简单的功能:
int* dummy(){
int test = 4;
int *t2;
t2 = &test;
return t2;
}
此函数初始化一个指针,并将一个 int 初始化为局部变量(不应在我的函数之外访问,因为一旦我退出函数,堆栈状态将恢复)。但是,我将指针作为函数的结果返回。 我可以取回指针并打印我的局部变量的值:
#include <stdio.h>
int main(void){
int* p = dummy();
// some other calls to other functions to mess up the bellow stack,
// where my local variable "test" was supposed to be landing
printf("%d\n", *p); // printing the value of "test" (which is 4)
}
结果
$ ./a.out
4
为什么打印出正确的结果?指针不是从其他状态指向堆栈中的变量吗?我很困惑。
如果内存在没有动态分配的情况下停留在某个地方,它会停留在哪里?是不是永远失去了? (没有办法“释放”它)
在 cmets 之后编辑
行为未定义。为警告添加编译器选项(例如pedantic)将打印一条警告,指出我正在返回一个指向局部变量的指针,并且可执行文件会出现错误。
原因是当程序存在函数时dummy的堆栈状态会丢失,因此不能保证局部变量的值,因为它们是......局部的。
【问题讨论】:
-
虽然技术上未定义行为,但它只是“碰巧起作用”,因为堆栈地址仍然存在。在
dummy和printf之间调用其他函数,堆栈内存会被其他函数的局部变量值覆盖。 -
尝试在通话后添加
int x, y, z = 1, 2, 3。 -
@selbie 这就是我一直在尝试的。可能不足以覆盖变量。
-
基本上,
int test = 4;将 4 放在某个内存位置或寄存器或其他东西中。然后你从函数返回,编译器会忘记它。然后你访问那个位置,它仍然包含值 4 是巧合,因为编译器没有看到任何理由花费时钟周期来删除它。该值仍然存在,这完全是巧合——如果你在运行函数和使用返回值之间运行了其他代码,任何事情都可能发生(计算机甚至可能着火——我是认真的) -
@selbie 用 -O2 编译确实给我打印了一个警告,告诉我我正在返回一个指向局部变量的指针,并使整个事情变得错误。这就是我一直在寻找的,非常感谢。