变量声明启示(一)

来源:互联网 发布:51单片机可调时钟程序 编辑:程序博客网 时间:2024/05/16 06:17

      昨天闲来无事,在Linux下编了一个小程序,没有什么算法,但是出现了一个大问题,仔细检查,发现问题所在,然后通过测试就牵出了一个以前没有怎么注意到的东西,特此留念,警示一下自己。

      首先给出一段简单的不能再简单的源代码:

 

编译执行后,首先会输出 a = 1234 ,然后需要输入一个字符数组,如果这里你输入的是少于3个字符包括3个(例如123或abc),那么下一句输出 a = 1234 ,但是如果你输入的是一个超过3个的字符(例如1234)的话,那么第二句输出的是 a = 1024,a的值发生了改变,但是程序根本没有涉及到对a的修改啊。

      其实,原因出在了你输入的字符数组b上,对于b,程序中给它申请了4个字符的空间,当你输入4个字符(例如1234)的时候,其实你是向这个字符数组中存入了5个值,第5个值就是我们忽略的回车键,而当你输入超过4个字符的时候,就更显而易见了,就是你使得这个字符数组越界了!

      为什么越界就会使毫不相干的另一个变量发生变化呢?原因出在变量的存储地址上,对于上面的程序,程序运行的时候,首先碰到一个int类型的变量a,编译器会把它先存入数据栈中,也就是放在了栈低,然后又碰到了一个char型的长度为4的字符数组,就又把它入栈,而且是放在了a的上面,这时a和b的地址就是连接起来的,试想一下,如果你的b变量写多了,那么就会超出自己的地址空间,也就到达了a的地址空间,相当于把a的值就给覆盖了一部分,就把a的值给改变了,这就是原因所在。

      本在无聊的精神,我把上面的程序修改了一下,就更能体会到刚才的观点了:

 

其实只是把两个变量的声明顺序调换了一下,但是这样一来,就是b这个字符数组先进栈,a在它的上面存放,如果这时b越界了,那么它的“魔爪”就会向栈底的下面伸去,就像是把栈的地盘打破了,把下面的东西覆盖修改了,但是a还是完好无损的在它上面保留着。通过实践证明,对于上面这段代码,无论b输入什么,a都不会改变的,这也就应证了刚才的理论。

      但是我并不是说提倡第二种这样的解决办法,因为它的a没有改变,只是针对这个程序是好的,但是b的越界终究还是引起了一些其他地方的改变,程序还是有bug的,所以最终的解决办法,当然就是对b的越界进行检测,如果越界了就取消操作,提示错误。对于C语言来说,它是不会自动检测数组越界问题的,因为如果这样消耗就太过庞大了,所以都是编程人员自己对数组进行检测的。

      总结一下,说这些东西的目的其实不是让你把数组先定义,其实是为了让我们记住对于数组来说,如果不对它进行越界检测,会产生大麻烦的。对于一个程序成品来说,使用者不可能会看到你定义的数组的长度是多少的,所以为了程序的可靠性,就要对多方面进行谨慎的保护。

原创粉丝点击