C语言自动变量的潜在问题

关于C语言自动变量的一个基本规则是:声明自动变量的函数已经返回后,不能再引用这些自动变量。

下面就此问题进行测试。
测试环境:
    编译器:GCC 4.2.4
    OS:Ubuntu 8.04 LTS

首先编写一个简单的C程序,暂且命名为test_auto_val.c。 

 

在这个程序中,main()函数里面的ptr指针引用了已经返回的函数func1()中声明的自动变量val。
编译运行这个程序,输出结果为5,看起来似乎并没有出现问题,但是我们的确引用了已经返回的函数中声明的自动变量。

接下来,修改test_auto_val.c的内容,将main()函数修改为: 

 

只是增加了一条printf语句,并且与上一行一模一样。在我的系统的本次运行中,得到的结果是:
    5
    -1078398860
问题出现了,为什么两次输出会不一样呢?

程序运行时,系统会为之分配一个栈,而程序中的每个函数在被调用时会占据这个栈的一部分,称为这个函数的栈帧,自动变量的存储空间就分配在函数的栈帧上。

现在来分析这两个程序的运行。

第一个程序运行时,系统为之分配栈空间,然后main()函数被调用,在栈空间里创建自己的栈帧。随后,在main()函数中func1()被调用,func1()也在栈空间创建自己的栈帧。func1()的栈帧在main()的栈帧之下(假设栈顶向低地址扩展),自动变量val分配在func1()的栈帧上。当func1()返回后,逻辑上认为func1()的栈帧已经不存在。但是,事实上在栈空间中,为自动变量val分配的内存单元并没有被改变。因此,当我们在main()函数中使用指针引用其值时,仍然得到了正确的结果。

那修改以后的程序为什么会得到两个不同的值呢?因为printf()函数被调用时也会创建栈帧,而这个栈帧覆盖了func1()的栈帧曾使用过的空间,破坏了自动变量val的内存单元的值。事实上,当我们执行第一条printf语句时,我们将*ptr(注意,这已经是一个int类型的值)作为参数传递给printf()函数,而在进行*ptr这个运算的时候,printf()函数尚未被调用,因此我们得到了正确的值。而执行第二条printf语句时,上一次的printf()函数的调用已经破坏了func1()的栈帧曾使用过的栈空间,因而不能再得到val的值。

下面,再次修改test_auto_val.c来验证以上分析: 

 

增加了函数func2(),并且在main()函数中执行第一条printf语句后调用func2(),然后再次输出ptr指向的内存单元的值。在func2()中定义了与func1()相同的变量,目的是以同样的结构覆盖func1()的栈帧。
运行程序,得到如下结果:
    5
    9
从运行结果可以看出func1()的栈帧确实被func2()覆盖了。

前面提到了*ptr作为参数调用printf()函数之时已经是一个int类型的值,也就是说printf()函数被调用前我们已经取出了val内存单元的值,正因为如此,printf()函数才会输出正确的结果。事实上,如果我们用字符串来做这个测试将不能在main()函数中输出字符串的值。同样,可以通过修改test_auto_val.c来验证:

 

运行程序,输出的很有可能是乱码,或者是其它东西,总之不是我们在func1()中定义的字符串。这是因为对字符串的访问是在printf()函数调用以后通过作为参数传入的ptr指针来实现的,而此时func1()的栈帧已经被printf()的栈帧覆盖了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值