三分钟弄清楚C语言为何函数退出就不能使用局部变量了,不初始化局部变量会出错吗
发表于: 2018-11-02 12:00:03 | 已被阅读: 46 | 分类于: C语言
为什么函数返回时,局部变量就不能用了
程序每调用一个函数,系统就自动在栈区划分一块区域给该函数使用,函数内部定义的局部变量,也存在此处。因为并不能知道系统分配的栈区原来填充的是什么样的数据,所以如果函数内部定义的局部变量没有初始化(没有赋初值)就使用它,它的值也是未知的。
当函数执行完毕,返回时,系统将收回这块分配的栈区,所以函数的局部变量的值就不能继续使用了。
说了这么多空的,我们来看一个例子,下面的代码非常简单,就是在 test 函数中定一个了一个局部 int 型变量 i,然后打印出它的值,再赋值为 321,然后在 main 函数中调用 它两次。
#include <stdio.h>
int test(void)
{
int i;
printf("%d\n", i);
i = 321;
}
int main(void)
{
test();
test();
return 0;
}
134567128
321
出乎意料,第二次打印出的值正是第一个 test 末尾赋的值 321。有一种初学者是这样,原本就没有把这条语法规则记牢,或者对自己的记忆力没信心,看到这个结果就会想:哦那肯定是我记错了,改过来记吧,应该是“函数中的局部变量具有一直存在的固定的存储空间,每次函数调用时使用它,返回时也不释放,再次调用函数时它应该还能保持上次的值”。
还有一种初学者是怀疑论者或不可知论者,看到这个结果就会想:教材上明明说“局部变量的存储空间在每次函数调用时分配,在函数返回时释放”,那一定是教材写错了,教材也是人写的,是人写的就难免出错,哦,连C99也这么写的啊,C99也是人写的,也难免出错,或者C99也许没错,但是反正运行结果就是错了,计算机这东西真靠不住,太容易受电磁干扰和宇宙射线影响了,我的程序写得再正确也有可能被干扰得不能正确运行。
这两种想法当然不对。我们说,
函数返回后,系统收回原分配的栈区,却不一定会去清零它。如果下一次,恰好又把这块栈区分配给 test 函数,局部变量 i 所在的区域恰好是上一次 i 所在的区域,而上次 test 函数返回之前,把这块区域赋值为 321 了,那这次 i 的“未知值”就正好是 321 也就不奇怪了,对吧。
为了验证我们上面的解答,我们在两个 test 之间加一行 printf,再做次实验:
...
int main(void)
{
test();
printf("something\n");
test();
return 0;
}
再编译执行,发现输出为
134567128
something
0
看到没,第一个 test 函数末尾赋的值,并不能保证一定传给下一次 test。
未初始化的局部变量的值是不确定的,上一次谁使用过这一块的栈区,恰好留在局部变量所在区域的值等于几,这次局部变量的未初始化的默认值就是几。
全局变量为什么可以一直保留到程序结束?
这是因为,全局变量要么保存在 bss 段,要么保存在 data 段,这两个段会一直保留到程序结束。
未初始化的全局变量保存在 bss 段,已初始化的全局变量保存在 data 段。