问题的引出
在进入今天的正题前,先来看一道题:
下面这个程序,屏幕上会显示几行数组?
5行?emmm……嘿嘿……我们稍后再揭晓。
问题的产生
最近我看到一道c++的编程题:
求12的100次方结果的末三位
当然,题目本身并不难,简单分析如下:
不能傻乎乎的写个for循环从1到100,把12的100次方结果算出来……理论上这样做没问题,但是现实是残酷的,你会把计算机算成死机的。
当然,要达到题目要求,结果还是要计算出来的,只不过我们选择间接计算——题目要求末三位,那咱们就只要每一次的结果的末三位,其余位抛弃好了。
基于上述分析,最后的程序可以这样写:
我们编译运行一下,输入100,结果如下:
那程序结果到底对不对呢?100的结果没法直接验证,那我们输入4、5、6简单验证看一下结果:
用计算器算一下:
12^4=20736
12^5=248832
12^6=2985984
看来结果令人很满意!
然而……
我在写出上述程序之前,是另外一种写法:
唯一不同的是,将每一次结果的后三位通过模取,分别存储到三个数组中,如下:
在Microsoft Visual C++6.0(以下简称VC)中编译执行程序,然而执行结果与我想象中的有所差异:
小南瓜
咦?宝宝明明输入的n是6呀,咋输出变成了2?程序中没有一条语句有修改n的呀!
无奈之下,我这个编程小白求助了檀大佬,大佬看了半天然后给出了最后的结论:
随后,大佬又给出了一个建议:
于是很快,我在DEV C++(以下简称 )中再次编译运行了一遍,结果依旧一样!
随后我又在一个大佬云集的群里求助请教,与此同时,我决定在Visual Studio 2017(以下简称VS)中再试一遍。
我惊愕的发现,是正常的:
此时,群里刘大佬传来反馈:
大佬就是大佬,一针见血的指出了要害……确实是循环里数组访问越界了………………解决了困惑我一晚上的问题!
然而……
重点是:为啥,循环里访问数组越界,n值会被修改?
问题的解决
为了方便调试,我在程序中添加了几行具有显示作用的代码,如下:
输入6,进行调试,结果发现,在循环中访问数组越界,n的值的确会被某种神秘的力量修改!!!!!
细思极恐啊啊啊……
然而……
重点是:此时,我们回到一开始文章开头抛出的问题:下面给出的程序,最终输出在屏幕上的有几行?
经过简单的分析发现,在这个循环中同样存在数组越界的情况,那么它最终会在屏幕上输出几行呢?
通过GIF可以看到,最后输出在屏幕上的是一个无限死循环……纳尼?这是什么操作??
小伙伴
这是为什么呢?
为了说明更加清楚,我们对程序稍作修改如下:
即增加了内存地址的输出,编译运行结果如下:
可以看到,内存地址是循环变化的,我们通过画图来说明问题:
进入循环后,前四次对数组依次赋值为1,这很常规,关键是接下来的分析;
由于一开始定义数组时,定义为:arr[5],即告诉编译器开辟arr[0]、arr[1]、arr[2]、arr[3]、arr[4]这五个空间(整形数组,故一个数组长度为4个字节,所以地址间隔4)。于是乎,在下一个地址号:0019FF3C,程序存放变量i值,如下图:
所以,可以很直观的看到,实际上arr[5]和i指向的是同一个地址空间,于是,接下来执行“arr[5] = 1”,实际上就是等同于执行“i = 1”。由于循环结束的条件是“i
(关于i存放地址为啥子是0019FF3C,可以加一个输出i地址的语句,输出看看就知道了。)
至此,我们明白了,为什么在循环里访问数组越界,很容易造成死循环,原因就是在于,在越界的地方赋值,其实等同于修改循环变量i的值,假如凑巧此时修改的i值满足了跳出循环条件,自然而然就不会出现死循环。
所以,这也解决的我的疑惑,“谁动了我的n值?”,答案是循环赋值越界数组修改的!
那么,根据以上分析,原先我写的那个求12^100的程序,n值应该等于越界赋值的数组的值,即n应该等于change[3]的值,我们运行一下,发现结果的确如此,也证明了我们的分析是正确的!
然而……
嗯mmm,这回是重点了!
可是……
还有一个重点:为啥在VC和DEV中出现了死循环,而在VS中运行,却没有出现修改循环变量的情况呢?
为了简单起见,我们运行文章开头的程序。
经过简单的debug,很快发现端倪,看下图:
本来i值理论上不会超过5,但是此时i被编译器修改成了6,由此可见,VS的编译器不同于VC和DEV的编译器,VS的编译器会自动为越界的数组动态的增加一个内存,但是,很遗憾,这种增加,会引起编译器的运行时异常:
至此,关于循环访问数组越界问题,彻底解决。通过本次研究,我们从中得出一个结论:对于c++的编译器,在编译程序时不会对数组越界产生任何警告或错误,这就对我们程序的执行造成了隐藏的祸患。所以在以后的编程中,尽量做到:
数组定义不越界,凡是使用到数组的地方,第一反应就是检查其是否越界;
最好选择使用动态数组,这样是防止数组越界的最有效的方法。
我猜你还想看
文稿/排版/图片:小南瓜
领取专属 10元无门槛券
私享最新 技术干货