2012-02-27 48 views
14
#include<stdio.h> 

int main() 
{ 
    char *name = "Vikram"; 
    printf("%s",name); 
    name[1]='s'; 
    printf("%s",name); 
    return 0; 
} 

終端上沒有打印輸出,只是出現分段錯誤。但是,當我在GDB運行它,我獲得以下 -執行printf()和分割錯誤

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000400525 in main() at seg2.c:7 
7  name[1]='s'; 
(gdb) 

這意味着程序收到七號線賽格故障(顯然我不能恆字符數組寫)。那麼爲什麼第6行的printf()沒有被執行?

+0

我不太確定。它在運行OSX Lion的Mac上按預期工作(符合LLVM,使用LLDB調試)。 – 2012-02-27 18:02:27

回答

30

這是由於流stdout緩衝。除非你做fflush(stdout)或你打印換行"\n"輸出可能會被緩衝。

在這種情況下,緩衝器被刷新,並打印之前它的段錯誤。

可以代替試試這個:

printf("%s",name); 
fflush(stdout);  // Flush the stream. 
name[1]='s';   // Segfault here (undefined behavior) 

或:

printf("%s\n",name); // Flush the stream with '\n' 
name[1]='s';   // Segfault here (undefined behavior) 
+6

請注意,'fflush'確實是這樣做的正確方法 - 換行符不能保證觸發刷新(並且之前我被這種行爲咬過)。 – 2012-02-27 18:30:51

4

的原因,你得到一個分割故障原因是C字符串文字是根據C標準只讀,並且你正試圖在字面數組「Vikram」的第二個元素上寫's'。

你越來越沒有輸出的原因是因爲你的程序緩衝輸出和崩潰它有機會刷新其緩衝區之前。除了提供友好的格式化函數(如printf(3))之外,stdio庫的目的是通過緩衝內存緩衝區中的數據並僅在必要時清除輸出並僅偶爾執行輸入來減少I/O操作的開銷而不是一直。在一般情況下,實際的輸入和輸出不會在您調用stdio函數的時刻發生,但只有在輸出緩衝區已滿(或輸入緩衝區爲空)時纔會發生。

事情是,如果一個文件對象已設置略有不同所以它不斷刷新(如標準錯誤),但總的來說,這是要點。

如果你正在調試,最好是fprintf中到stderr,以確保您的調試打印輸出將在崩潰之前就臉紅。

9

首先你應該用「\ n」(或者至少是最後一個)來結束你的printfs。但是這與segfault無關。

當編譯器編譯你的代碼,它將該二進制分成幾個部分。有些是隻讀的,而另一些是可寫的。 寫入只讀部分可能會導致段錯誤。 字符串文字通常放在只讀部分(gcc應該把它放在「.rodata」中)。 指針名稱指向該ro部分。因此,您必須使用

const char *name = "Vikram"; 

在我的回覆中,我用了幾個「可能」「應該」。行爲取決於您的操作系統,編譯器和編譯設置(鏈接器腳本定義了各個部分)。

添加

-Wa,-ahlms=myfile.lst 

到GCC的命令行產生稱爲myfile.lst與所生成的彙編代碼的文件。 在頂部,你可以看到

.section .rodata 
.LC0: 
    .string "Vikram" 

這說明該字符串在維克拉姆。

相同的代碼使用(必須在全球範圍內,其他的gcc可以將其存儲在堆棧中,注意到它是一個數組,而不是一個指針)

char name[] = "Vikram"; 

產生

.data 
    .type name, @object 
    .size name, 7 
name: 
    .string "Vikram" 

的語法有點不同,但現在看它是如何在.data節中的,它是可讀寫的。 順便說一句,這個例子的作品。

+1

如果您注意到,OP不會問爲什麼發生段錯誤,但爲什麼字符串不是首先打印出來的。 – 2012-02-27 18:39:40

+1

雖然這可能不是完全回答這個問題,但提示和解釋.rodata和.data是有幫助的。 – vts 2014-05-08 16:16:19

0

默認情況下,當stdout連接到終端時,該流是行緩衝的。實際上,在你的例子中,缺少'\n'(或明確的數據流清除)就是爲什麼你不能打印字符。

但理論上不確定的行爲是無界(從標準「的行爲[...]該標準並沒有規定要求」)和發生之前的不確定的行爲,例如前可能發生的段錯誤第一個printf電話!

+0

所以......你說的行爲是如此不明確,以至於它可能會及時向後行動*? – 2017-03-29 19:17:10