初始化局部变量,什么时候发生?

时间:2016-10-18 17:27:50

标签: c undefined-behavior

我刚刚学习了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或其他功能)

但为什么呢?我的代码或其他什么不对?

2 个答案:

答案 0 :(得分:3)

您可能知道,返回本地变量的地址,然后尝试取消引用该地址为undefined behavior

这意味着您的程序可能会崩溃,它可能会出现奇怪的行为,或者它似乎可以正常工作。对于相同的代码或存在看似无关的更改,此行为不需要从一个编译器到下一个编译器保持一致。

话虽这么说,许多编译器通常不会修改函数返回后使用的堆栈部分。这是通常不需要的额外工作。所以在fuc返回后立即,它所包含的局部变量仍包含旧值。

在调用printf时,在调用poin2之前取消引用指针printf。由于在此之前没有调用其他函数,因此上次调用afunc的值尚未被覆盖。所以你读了旧值。

当您在循环中调用printf时,第一个调用可以像以前一样获取a的值。但是,调用printf然后修改堆栈。具体来说,存储a的内存位置会被其他内容覆盖。因此,在对printf的后续调用中,它会读取该内存位置中最后一次调用printf的内容。

但重申一下,这是未定义的行为。并非所有编译器都需要以这种方式运行。例如,在高安全性环境中,编译器可能会在函数返回后清除堆栈内存,以便无法恢复该函数使用的敏感数据。

答案 1 :(得分:1)

辅助函数中的局部变量'a'位于堆栈中。在帮助程序的末尾,堆栈展开,但堆栈框架没有显式清零...它就在那里。当你调用printf时,它会用printf的堆栈帧覆盖堆栈帧,那就是重新使用内存的时候。请注意,第一次调用printf时,取消引用内存并在分配/初始化printf堆栈帧之前通过值传递'2',这就是您第一次看到'2'的原因。