2017-04-12 43 views
-4
#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    int step; 
    double position[4]; 
    position[0] = 1; 
    for (step = 1;step<=4;step++){ 
     position[step] = 99; 
    } 
    return 0; 

} 

可以編譯沒有錯誤,並且生成的程序可以運行。C:數組錯誤初始化的奇怪行爲

然而,

#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    int step; 
    double position[3]; 
    position[0] = 1; 
    for (step = 1;step<=3;step++){ 
     position[step] = 99; 
    } 
    return 0; 

} 

也可以編譯,但程序不能運行:錯誤是Abort trap: 6

在上述兩種情況下,(錯誤地)初始化數組的大小爲1小於我在填for循環的。但爲什麼43在這裏有所作爲?

現在,更有趣的是,

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <math.h> 

int main() { 
    int step; 
    double position[4]; 
    position[0] = 1; 
    position[1] = 99; 
    position[2] = 99; 
    position[3] = 99; 
    position[4] = 99; 
    return 0; 
} 

甚至不能編譯(錯誤是array index 4 is past the end of the array (which contains 4 elements)。那麼爲什麼for循環在這裏有所作爲?

+4

存在'C'沒有數組邊界檢查。它會有未定義的行爲。 –

+4

這是**未定義的行爲**。標準不保證*任何*;可能有也可能不會有編譯錯誤或運行時錯誤。它甚至可能會擦除所有數據,因爲沒有保證。 – ikh

+0

在前兩種情況下,將在運行時對數組賦值。但在第三種情況下,它將在編譯時。所以它會拋出錯誤。 – Rajeshkumar

回答

1

在第三種情況下,編譯器提醒您的越界訪問。該標準不要求它抱怨,但它是這樣做的。

對於前兩種情況下,有思維正在發生的事情沒有任何意義。你說第一個程序運行罰款。它沒有 - 它有一個UB。

爲了您的約3 & 4如何改變任何東西,它可能是依賴於堆棧幀是如何奠定了問題。由於對齊差異,返回地址可能在一種情況下被丟棄,但在另一種情況下則不會。您將不得不查看生成的程序集文件以查看實際出錯的內容。

https://godbolt.org/g/gqz39q表明,在情況下設置數組大小爲3則放置在position%rbp - 32step%rbp - 4。所以如果你寫position[3]step被覆蓋(我不想考慮寫什麼)。

當你的position大小爲4,它把step%rbp - 4position%rbp - 48。現在你寫信給position[4]%rbp - 48 + 4 * 8 = %rbp - 16。這將寫入,直到%rbp - 8。所以%rbp - 4step)沒有改變。

長話短說,填充救了你的情況下,1但不是在案件2

PS:這又是具體到選擇的編譯器GCC 6.2 O0優化級別。原因可能在你的情況下完全不同。

+0

是的。奇怪的是'4'沒有顯示任何符號,但'3'確實給我一些警告。此外,'for'循環顯然會做更多的事情,並且在這個意義上「更安全」。 – kyle

1

有在C語言中提到什麼,阻止你從編寫訪問外邊界內存的代碼,標準只是明確提到,這樣做的任何企圖將導致undefined behavior

任何診斷,如果提供的是在編譯器,也許綁在供給編譯選項的自行決定,標準提到的此不作要求。

例如,for some compiler, the last snippet compiles just fine(並接收運行時錯誤,太)。

注1:在圖示的片段,該聲明初始化,他們分配

注2:我修改一下代碼,但無效的訪問取得相同

#include <stdio.h> 

int main(void) { 
    //int step;    // remove unused variable warning 
    double position[4]; 
    position[0] = 1; 
    position[1] = 99; 
    position[2] = 99; 
    position[3] = 99; 
    position[4] = 99; 

    (void) position;   // suppress unused variable warning 

    return 0; 
}