C销毁局部变量的疑问

C语言的局部变量在超出作用域后会自动销毁,但是被销毁的局部变量还是有可能读取原来的值的,

 

先说一下环境,VS2017,

下面的操作是寻址调用子函数里被释放的int局部变量的值并打印,

发现可以通过寻址找到局部变量被销毁前的值,但是第二次寻址发现值改变了。

 

为什么局部变量被销毁后,还可以通过寻址找到变量的值?

C中的局部变量在栈上分配空间,局部变量作用域内,我们可以通过变量名找到对应的地址空间,读写变量

而“销毁局部变量”的具体操作是将局部变量名(上图的‘a’)指向另外的区域,这样我们编写程序时如果想要通过使用a读取那个地址空间存储的值,会报错,这就是销毁的过程,

但是,销毁相当于重置指针,将其指向不可访问处,并没有对原地址存储的值做什么,所以,如果我们找到了局部变量的地址,就可以再次对其进行读写,出现上面图片的情况。

 

为什么第二次的printf输出的值会改变?

多次试验,发现第二次寻址输出的值是int被初始化后的统一值 -858993460,也就是说在第一次读取变量值之后,第二次读取变量之前,原地址的值被初始化了,

那么中间发生了什么?

通过添加断点可以看出,在第一个printf之后,局部变量地址存储的值就被初始化了,

而如果将printf换成“ *int a=0;a++;”就不会导致初始化,

这说明,子函数的局部变量被销毁后,主函数后续执行的操作可能会导致初始化,也可能不会,

具体的解释需要更底层的东西,之后学习了会更新……

 

总结

销毁的过程是指针重置,这样节省开销,但是有缺陷的,不安全的,这种寻址会导致出现野指针,指针p就是野指针,

 

子函数定义的局部变量在返回主函数,被销毁之后,仍然可以通过p寻址找到局部变量的值,

但是这是未定义的行为,即不同的编译器可以自行处理这种情况,上面的代码在不同编译器上可能运行结果不同,

 

子函数的局部变量销毁后,主函数的操作可能会导致原地址的值被初始化覆盖,

 

所以,由于“销毁”的不彻底,被“销毁”的局部变量可以访问,但是局部变量的值不再保证有效,这样的访问行为是undefined behavior

 

另外,

如果是主函数花括号内定义的局部变量,

局部变量的类型不是int、char等简单类型,而是自己定义的结构体,

使用不同的编译器,

那么局部变量销毁后,原地址存储的值是不确定的,可能不变,也可能被初始化,也可能随机赋值,需要自己试验,只是选了一个示例进行记录

 

参考资料

百度百科 野指针

https://www.zhihu.com/question/269583338 ValarHa的回答

posted @ 2020-07-18 09:42  _lyl  阅读(895)  评论(0编辑  收藏  举报