我刚刚学习了C中的局部变量,并且书中说当局部变量的函数结束时,局部变量总是从内存中初始化。 所以我只是编写了一些代码(使用Visual Studio 2015)来确认。 这是代码:
#include <stdio.h>
int* poin2 = NULL;
void fuc(void);
int main(void) {
int a = 3;
fuc();
printf("%d %d\n", a, *poin2);
return 0;
}
void fuc(void)
{
int a = 2;
poin2 = &a;
}
起初,我认为它会显示3和垃圾编号,因为fuc结束了,fuc(不在main中)必须在内存中初始化,所以poin2没有任何意义。 但结果是:
3 2
为什么它没有从内存中删除?我测试了下一个代码来弄清楚:
#include <stdio.h>
int* poin2 = NULL;
void fuc(void);
int main(void) {
int a = 3;
int b = 1;
fuc();
while (1)
{
b++;
printf("%d %d\n", a, *poin2);
if (b > 5) break;
}
return 0;
}
void fuc(void)
{
int a = 2;
poin2 = &a;
}
我的想法是:初始化内存需要很短的时间,所以我想找到什么时候。结果:
3 2
3 -858993460
3 -858993460
3 -858993460
3 -858993460
我用更多的代码测试了它,并且我发现当一个具有局部变量的函数完成时,它就改变了,就在另一个函数完成时。 (我的意思是当fuc()完成时它没有被移除,当printf完成时它被删除了, 并且它不依赖于什么功能,不仅仅是printf,还有scanf或其他功能)
但为什么呢?我的代码或其他什么不对?
答案 0 :(得分:3)
您可能知道,返回本地变量的地址,然后尝试取消引用该地址为undefined behavior。
这意味着您的程序可能会崩溃,它可能会出现奇怪的行为,或者它似乎可以正常工作。对于相同的代码或存在看似无关的更改,此行为不需要从一个编译器到下一个编译器保持一致。
话虽这么说,许多编译器通常不会修改函数返回后使用的堆栈部分。这是通常不需要的额外工作。所以在fuc
返回后立即,它所包含的局部变量仍包含旧值。
在调用printf
时,在调用poin2
之前取消引用指针printf
。由于在此之前没有调用其他函数,因此上次调用a
时func
的值尚未被覆盖。所以你读了旧值。
当您在循环中调用printf
时,第一个调用可以像以前一样获取a
的值。但是,调用printf
然后修改堆栈。具体来说,存储a
的内存位置会被其他内容覆盖。因此,在对printf
的后续调用中,它会读取该内存位置中最后一次调用printf
的内容。
但重申一下,这是未定义的行为。并非所有编译器都需要以这种方式运行。例如,在高安全性环境中,编译器可能会在函数返回后清除堆栈内存,以便无法恢复该函数使用的敏感数据。
答案 1 :(得分:1)
辅助函数中的局部变量'a'位于堆栈中。在帮助程序的末尾,堆栈展开,但堆栈框架没有显式清零...它就在那里。当你调用printf时,它会用printf的堆栈帧覆盖堆栈帧,那就是重新使用内存的时候。请注意,第一次调用printf时,取消引用内存并在分配/初始化printf堆栈帧之前通过值传递'2',这就是您第一次看到'2'的原因。