曾經有一家公司有一道面試題目如下:
在Linux x86_64 gcc環境下,下面的程式會出現什么問題?運行結果是什么?為什么?

肯定很多面試者看到了就立馬說:“陣列越界了嘛,”
確實如此,但是結果是什么呢?想必很多人都是不知道的,結果是死回圈列印數字,讓我們來分析分析,
因為我用的是VS編譯器,那么我這里就寫一個和題目相仿的題來分析:
#include <stdio.h>
int main()
{
long i;
long arr[16];
for (i = 0; i <= 18; i++)
{
arr[i] = 0;
printf("%d",i);
}
return 0;
}
代碼的結果是死回圈列印數字,準確來說我這道題是死回圈列印0-17的數字,那么原因是什么呢?
-
當我們除錯起來的時候可以看到:

因為剛開始我們并沒有給變數i和arr陣列初始值,所以他們剛開始的值都為隨機值,這都沒有什么問題, -
當我們按F10繼續除錯時可以觀察到,陣列中的元素也一一被賦值為0,i的值也隨之增加:

-
走到越界后的arr[16]和arr[17]時:

我們發現雖然陣列以及越界但是我們確確實實吧arr[16]和arr[17]的值也賦值為0了,這個問題也不大,因為語言本身是不做越界檢查的 -
當除錯到后面將arr[18]也賦值為0時發現,i的值也被賦值為0:
這是為什么呢?其實善于觀察的朋友們會發現arr[18]和i的值一開始就是一樣的(不信你再看看前面幾張圖),于是我們會想:難道arr[18]里面就是i的值嗎? -
想知道這個也不難,我們只需要看看他們在記憶體中的地址是否相同即可:

看到他們的地址確實相同,這也說明了他們都表示同一個數,那么原理是什么呢?
原理:
首先i和arr陣列都是區域變數,所以他們都是放在記憶體中的堆疊區上的,而堆疊區記憶體的使用有一個規定:先使用高地址處的空間,再使用低地址處的空間,
而陣列也有一個規定:陣列隨著下標的變化,地址由低到高,
因為i變數定義在arr陣列之前,所以i變數的地址就比arr陣列的高,這樣我們可以通過畫圖來解釋:

所以,當陣列適當越界得情況下,就可能導致越界訪問到回圈變數i,改變i得值就可能導致死回圈,
這樣,i的值就一直回圈地從0-17,也就是回圈列印0-17得數字了,
相信有博友會質疑為什么一定i和arr陣列之間就恰好各了兩個空格(也就是8個位元組)呢?這難道不是巧合嗎?
確實,編譯器不同i和arr陣列之間所差的位元組不同,而在VS編譯器下就差8個位元組,但是在開頭所說的Linux x86_64 gcc環境下,它們所差的就是4個位元組(也就是一個格子),所以我在VS編譯器中運行時就故意將題中的條件:i<=17改為了i<=18,這樣才能變為死回圈,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/254096.html
標籤:其他
上一篇:DPDK的基本原理、學習路線總結
下一篇:談談Epoll是如何作業的?
