1. 程式人生 > >g++ 記憶體分配 與 c 語言中的 陣列越界問題 (一道有趣的面試題)

g++ 記憶體分配 與 c 語言中的 陣列越界問題 (一道有趣的面試題)

首先是一段程式:

# include <stdio.h>

int main(int argc, char* argv[]){
    int i = 0;
    int arr[3] = {0};
    for(; i<=3; i++){
        arr[i] = 0;
        printf("%d", i);
        printf("hello world!");
    }
    printf("end!");
    return 0;
}

先考慮一下: 會輸出什麼?會報錯麼?

一些時間 之後答案在下面:

||
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


答案是 : 會無限迴圈

很多人第一反應是 會出現陣列越界,導致程式報錯!這樣是對的,如果在正常編譯的情況下,會出現陣列越界的報錯,但是,如果用下面的 編寫命令,就會出現無線迴圈的輸出。

g++  -fno-stack-protector -o zxc test.c

為什麼會這樣呢? 一般編譯的時候是沒有加 ` -fno-stack-protector ` 選項的。加了之後 就是禁用了 堆疊記憶體保護,也就是對C語言的 程式漏洞缺少了保護!

詳細解釋:

C語言的記憶體分配主要有:

  1. 靜態記憶體分配。主要是在程式編譯之前對全域性變數、靜態變數
    進行記憶體分配,持續到整個程式執行時間期內。
  2. 棧記憶體分配。主要是對於函式的區域性變數進行記憶體分配。持續時間 是整個函式的執行時間或者說是區域性變數的存活時間。
  3. 堆記憶體分配。主要是對程式中動態記憶體進行分配,例如使用malloc 或是 new 分配新的記憶體的時候。使用free或delete進行釋放

堆疊記憶體分配:當陣列和變數在一起的時候,如果先定義變數再定義陣列會導致這兩個變數的地址位於相鄰,這樣在陣列越界的時候,就有可能訪問的變數的地址內容,而非陣列地址內容(前提是變數的型別和陣列型別一致)。所以上面的當訪問到a[3] 的時候,實際上是訪問的 i 的地址,當賦值為0 的時候也就是把i 賦值為0了。所以就會無限迴圈下去。(因為預設情況下,在編譯時,是有堆疊保護的,不會出現無限迴圈的情況,但是關閉了堆疊保護就會了)

可以參考:https://blog.csdn.net/u012796139/article/details/46635567