2012-10-11 140 views
0

可能重複:
Why don’t I get a segmentation fault when I write beyond the end of an array?爲什麼我不會出現分段錯誤?

我只是用指針玩的時候,我意識到,一些奇怪的事情正在發生。我知道,每當我們要爲一個字符串SRC複製到另一個字符串DST,使用的strcpy,比如,我們應該分配所需的空間SRC

char *dst,*src = "asdlskafksdhfklshfkshdkfhksdhfçsahdflçsdhfçklshadfç"; 

    dst = (char*)malloc(1); //only one char allocated 
    strcpy(dst,src); 

    printf("dst=%s.\n",dst); 

此代碼不應執行。但是,這並沒有發生。該代碼執行後,將src成功複製爲dst並打印出dst就像一個魅力。請你解釋一下爲什麼會發生這種情況?

+9

它是未定義的行爲。它可能表現爲做程序員的意圖。或不。 –

+0

@DanielFischer:發明C的科學嚴謹的人從C規範中留下了很多細節,這是不是有點讓人失望? C中有很多「未定義的行爲特徵」! – Razvan

+0

@Razvan:這是非常有意的。 – akappa

回答

2

C的一部分性能是它沒有太多內置錯誤檢查的方式。所有的strcpy知道它傳遞了一個正確類型的指針,它不知道它指向多少分配的內存。生成的機器代碼只是從src指針讀取第一個空字節,然後將其粘貼到dst指針中。如果它不覆蓋別人的記憶,那就沒有錯誤。

什麼是「別人的記憶」?通常一個進程在pages中分配內存。當你malloc一個字節時,這個進程會被賦予一整頁的內存,可能只有幾千字節,可以根據需要進行切片和切塊。當您的流程嘗試在分配的頁面外寫入時,會出現分段錯誤,and for other reasons。該錯誤通常由執行內存管理的操作系統和/或硬件生成。由於src只有幾十個字節,因此不太可能走出進程的頁面。如果你使src的字符串更長,你可能會得到你期望的段錯誤。

有各種malloc包裝庫用於調試,通過各種技巧,使C檢查內存錯誤。 ValgrindElectric Fence是一些最有名的。

PS我對這些東西究竟是如何工作有點朦朧,但它比「它是未定義的行爲」更令人滿意。請隨時編輯我的解釋缺乏的地方。

+0

謝謝!我想我的'別人的記憶'這個概念是不正確的,或者是很模糊的。 我跑了Valgrind,它立即發現了問題。 ;) – Leaurus

+1

我可能會補充說'malloc'是管理由* kernel *(通常)分配的頁面的用戶空間庫的一部分。否則,你可能會遇到一些困惑:「當我調用free()'時,它是否也釋放整個頁面?」 – rliu

+0

但想象一下,整個頁面或幾個頁面在免費()呼叫時都是空的。然後他們被釋放,對吧? – Leaurus

1

在發佈版本* dst指向進程地址空間中的某些內存 - 如果它發生了寫入,如果它恰好被應用程序佔用,就像應用程序一樣,它會崩潰。

在調試版本中,您的編譯器可能會將* dst設置爲0或某些可識別的值(如0xDEADBEEF),因此您可以發現此問題。

1

如果您在外部分配的內存中寫入結果未定義。如果幸運的話,你會遇到段錯誤。如果你不幸,其他變量會被覆蓋。底線:什麼都行!

2

您的字符串分配在堆上。堆不具有僅1字節的大小,而是大約4kb的物理RAM(默認的Windows控制檯應用程序大小)。

嘗試寫入堆外的內存區域時,只會出現段錯誤。然而,你可能會破壞應用程序其他部分的內存。但是因爲你的程序非常小,並且在寫入超出分配的內存之後終止,所以你不可能看到任何錯誤

相關問題