2013-05-07 64 views
-1

這是C++中的for循環。我不明白爲什麼它沒有給執行分段錯誤。爲什麼這不會產生分段錯誤

int main() 
{ 
    int arr[5]; 
    for (int x = 0; x <= 5; x++) 
     { 
      arr[x] = x; 
     } 
    return 0; 
} 
+0

這是來自Java,Javascript和C#編碼的人......爲什麼會導致錯誤? – Renan 2013-05-07 20:46:14

+0

'for(int x = 0; x <5; ++ x)'。從零開始。 – gongzhitaao 2013-05-07 20:46:52

+0

@Renan該數組有5個索引爲0到4的元素。正在訪問索引5。 – 2013-05-07 20:47:18

回答

18

這是不確定的行爲。未定義行爲意味着什麼可以發生,包括:

  • 分段故障
  • 在所有
  • 輸出
  • 格式化硬盤
  • 的不一致沒有錯誤...(什麼)

爲了更形式化,這是C++ 11 Standard如何定義未定義的行爲:

行爲這本國際標準中並沒有規定要求 [:當本國際標準省略了 行爲的任何明確的定義或當一個程序使用一個錯誤的結構或錯誤的數據,可以預期的不確定的行爲。 允許不確定的行爲 範圍從具有不可預知的結果完全無視的情況下,在環境的記錄方式特性翻譯或 程序執行期間行爲(有或沒有發行 診斷消息),到終止翻譯或執行(發出診斷消息)。許多錯誤的程序結構不會導致未定義的行爲;他們需要被診斷。 末端注]

關於爲什麼做x[5]的原因確實是不確定的行爲,那是因爲x[5]相當於*(x + 5)(見第8.3.4/6),和第5.3.1/1關於一元運算符*規定了:

一元*操作者進行間接:至其所施加應的指針 對象類型,或指向函數類型和結果左值指的是表達對象或功能 表達要點。如果表達式的類型是「指針T,」結果的類型是 「T」 [...]

但由於x + 5不指向任何對象,並且上述段落確實未指定解引用這種指針應的結果,先前引用的句子適用什麼:

[...]當本國際標準忽略了行爲的任何明確定義未定義行爲可預期[...]

Whi ch表示x[5]是未定義的行爲。當用戶程序試圖做的一個發生

+1

爲什麼它是未定義的行爲? – someguy 2013-05-07 20:47:36

+2

@someguy,因爲它允許編譯器執行某些優化。 – chris 2013-05-07 20:48:05

+0

@someguy允許某些優化假定您編寫明確定義的代碼。 – 2013-05-07 20:48:13

3

段故障:

  • 訪問不允許到所述存儲器,諸如系統存儲器
  • 訪問所述存儲器的一部分的部分,其不存在(又名出界)

那麼,你是在實現您的數組中達到出界是正確的,並在最後循環迭代您正在訪問你的程序分配的內存之外的東西。它恰好是這樣的內存不是系統內存,它存在,所以它可以讓你閱讀它。

如果你運行這段代碼的次數足夠多,你最終應該得到一個分段錯誤,因爲它會碰巧放在系統內存或內存末端。

+0

我質疑最後一部分。在我所知道的具有虛擬內存的系統上,這種方式不起作用。每個程序都有自己的地址空間,並且不會干擾除共享內存以外的其他應用程序地址空間。 – drescherjm 2013-05-07 21:03:49

+1

最重要的是arr [5]在棧上。 – drescherjm 2013-05-07 21:05:38

1

我認爲Andy Prowl已經回答說它是未定義的行爲。

但是,如果你對它沒有崩潰的原因感興趣,至少在我的編譯器中,變量x被分配到緊跟在數組之後的堆棧中。當您將x指定爲arr[5]時,您實際上只是將x指定爲自己。

顯然這可能會因編譯器不同而不同。只是覺得你可能有興趣知道至少一個特定的編譯器在做什麼。