C销毁局部变量的疑问
C语言的局部变量在超出作用域后会自动销毁,但是被销毁的局部变量还是有可能读取原来的值的,
先说一下环境,VS2017,
下面的操作是寻址调用子函数里被释放的int局部变量的值并打印,
发现可以通过寻址找到局部变量被销毁前的值,但是第二次寻址发现值改变了。
为什么局部变量被销毁后,还可以通过寻址找到变量的值?
C中的局部变量在栈上分配空间,局部变量作用域内,我们可以通过变量名找到对应的地址空间,读写变量
而“销毁局部变量”的具体操作是将局部变量名(上图的‘a’)指向另外的区域,这样我们编写程序时如果想要通过使用a读取那个地址空间存储的值,会报错,这就是销毁的过程,
但是,销毁相当于重置指针,将其指向不可访问处,并没有对原地址存储的值做什么,所以,如果我们找到了局部变量的地址,就可以再次对其进行读写,出现上面图片的情况。
为什么第二次的printf输出的值会改变?
多次试验,发现第二次寻址输出的值是int被初始化后的统一值 -858993460,也就是说在第一次读取变量值之后,第二次读取变量之前,原地址的值被初始化了,
那么中间发生了什么?
通过添加断点可以看出,在第一个printf之后,局部变量地址存储的值就被初始化了,
而如果将printf换成“ *int a=0;a++;”就不会导致初始化,
这说明,子函数的局部变量被销毁后,主函数后续执行的操作可能会导致初始化,也可能不会,
具体的解释需要更底层的东西,之后学习了会更新……
总结
销毁的过程是指针重置,这样节省开销,但是有缺陷的,不安全的,这种寻址会导致出现野指针,指针p就是野指针,
子函数定义的局部变量在返回主函数,被销毁之后,仍然可以通过p寻址找到局部变量的值,
但是这是未定义的行为,即不同的编译器可以自行处理这种情况,上面的代码在不同编译器上可能运行结果不同,
子函数的局部变量销毁后,主函数的操作可能会导致原地址的值被初始化覆盖,
所以,由于“销毁”的不彻底,被“销毁”的局部变量可以访问,但是局部变量的值不再保证有效,这样的访问行为是undefined behavior
另外,
如果是主函数花括号内定义的局部变量,
局部变量的类型不是int、char等简单类型,而是自己定义的结构体,
使用不同的编译器,
那么局部变量销毁后,原地址存储的值是不确定的,可能不变,也可能被初始化,也可能随机赋值,需要自己试验,只是选了一个示例进行记录