zoukankan      html  css  js  c++  java
  • 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的回答

  • 相关阅读:
    Python学习笔记 for windows 二
    Socket.io:有点意思
    MEAN Stack:创建RESTful web service
    在EC2上安装MEAN环境
    NodeJS:树的序列化
    NodeJS:树的反序列化
    NodeJS学习:爬虫小探补完计划
    NodeJS学习:爬虫小探
    依赖包bcrypt安装Issues
    Mongoose:Schema之路
  • 原文地址:https://www.cnblogs.com/lylhome/p/13334605.html
Copyright © 2011-2022 走看看