2011-08-04 54 views
2

有了這個代碼,我得到一個分段錯誤:爲什麼更改非const char *的分段錯誤?

char* inputStr = "abcde"; 
    *(inputStr+1)='f'; 

如果代碼是:

const char* inputStr = "abcde"; 
    *(inputStr+1)='f'; 

我會得到編譯錯誤「指定只讀位置」。 但是,對於第一種情況,沒有編譯錯誤;只是分配操作實際發生時的分段錯誤。

任何人都可以解釋這一點嗎?

+1

新的智能編譯器,像GCC,會警告你這一點。 – 2011-08-04 22:17:20

回答

5

這裏是什麼標準說,大約在部分字符串字面量[2.13.4/2]:

字符串文字,做不以u開頭,U或L是一個普通的字符串,也被稱爲窄字符串。普通字符串文字的類型是,其中n是如下面所定義的字符串的大小「N常量字符的數組」;它具有靜態存儲持續時間(3.7),並使用給定字符進行初始化。

所以,嚴格地說, 「ABCDE」 的類型是

const char[6] 

現在發生的事情在你的代碼是分配允許隱式轉換到

char* 

左右。之所以如此,可能是與C的兼容性。看看這裏的討論吧:http://learningcppisfun.blogspot.com/2009/07/string-literals-in-c.html

一旦轉換完成,你可以在語法上自由修改文字,但它會失敗,因爲編譯器存儲正如標準本身所允許的,它是一段不可寫的內存段。

0

儘管"abcde"是一個字符串文本,不應該修改,但您已經告訴編譯器,您不關心這個問題,因爲非const char*指向它。

編譯器會高興地認爲你知道你在做什麼,而不是拋出錯誤。但是,如果確實嘗試修改字符串文字,在運行時代碼很可能會失敗。

2

該標準規定,你不能直接修改字符串常量,不管你是否將它們標記const與否:

是否所有的字符串文字是不同的(即存儲在不重疊的對象中)是實現定義的。試圖修改字符串文字的效果是未定義的。

事實上,在C(不像C++),字符串文字const但你還是不能給他們寫信。

上書寫,該限制允許一定的優化的發生,例如沿着線文字的共享:

char *ermsg = "invalid option"; 
char *okmsg = "valid option"; 

其中okmsg實際上可以指向'v'字在ermsg,而不是一個明顯的串。

1

它主要是古代的歷史;曾經很久以前,字符串文字並不是一成不變的。但是,大多數現代編譯器將字符串文字放入只讀內存(通常是程序的文本段,代碼也位於此處),而任何嘗試更改字符串文字的操作都會產生核心轉儲或等效內容。

使用G ++,您肯定可以得到編譯警告(如果默認情況下未啓用,則爲-Wall)。例如,G ++ 4.6.0編譯在MacOS X 10.6.7(但運行在10.7)收率:

$ cat xx.cpp 
int main() 
{ 
    char* inputStr = "abcde"; 
    *(inputStr+1)='f'; 
} 
$ g++ -c xx.cpp 
xx.cpp: In function ‘int main()’: 
xx.cpp:3:22: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] 
$ 

所以警告默認啓用。

1

發生了什麼事是編譯器把常量"abcde"在一些只讀內存段。你指出你的(非const)char* inputStr在那個常數,KABOOM,段錯誤。要學習

經驗:不要調用未定義的行爲。

編輯(闡述)

但是,對於第一種情況,沒有編譯錯誤,只是分段錯誤的分配運算時實際發生的事情。

您需要啓用編譯器警告。始終將您的編譯器警告設置爲儘可能高。

0

字符串常量,而正式非const,幾乎總是存儲在只讀存儲器。在你的設置中,這顯然只是如果它被聲明爲const char數組的情況。

注意,標準禁止你修改任何文字字符串。

3

這得到代碼段創建:

char *a = "abcde"; 

本質上,它是常量。

如果您希望編輯它,嘗試:

char a[] = "abcde"; 
0

在裏奇的話字符串文字的歷史一點點。 主要是關於淵源考和字符串文字的給K & R第1 希望這可以解釋一兩件事常量和字符串文字的演變。

「來源:丹尼斯里奇 主題:回覆:歷史問題:字符串文本。 日期:1998年6月2日 新聞組:comp.std.c

當時的C89委員會,工作,可寫 字符串字面量不是「遺留代碼」(馬戈林),什麼標準 存在着(K (A.2.5) 字符串只是一種初始化靜態數組的方法。正如Barry指出的那樣,有一些(mktemp)例程使用了這個事實。 。

我不在身邊的委員會關於 點的討論,但我懷疑BSD實用程序擺弄 彙編代碼,大多數 移動串 的初始化成文本而不是數據,並且實現文字字符串實際上並未被覆蓋,比某些非常早期的gcc版本更重要。

我認爲委員會可能錯過了某些東西 未能找到一個公式解釋 字符串常量的行爲。 也就是說,如果「abc」是 const char [4] 類型的匿名文字,那麼它的幾乎所有屬性(包括 )都可以只讀,甚至可以共享其存儲 以及其他出現的相同的文字)幾乎解釋爲 。

的問題,這不僅是字符串文字實際上是寫在相對較少的 地方,但大部分 更重要的是,制定出切實可行的規則分配 的指針給const,特別是函數的實際 參數。實際上,委員會知道,無論他們制定的規則如何,都不需要對現有世界中的每個func(「字符串」)進行強制性的 診斷。

因此,他們決定離開普通字符數組「 」的類型,但說一個是不要寫在它上面。

本說明書BTW並不打算在C89中作爲鷸012 閱讀。很難讓東西 正確(連貫和正確)和可用(一致 足夠有吸引力)。

Dennis