有了這個代碼,我得到一個分段錯誤:爲什麼更改非const char *的分段錯誤?
char* inputStr = "abcde";
*(inputStr+1)='f';
如果代碼是:
const char* inputStr = "abcde";
*(inputStr+1)='f';
我會得到編譯錯誤「指定只讀位置」。 但是,對於第一種情況,沒有編譯錯誤;只是分配操作實際發生時的分段錯誤。
任何人都可以解釋這一點嗎?
有了這個代碼,我得到一個分段錯誤:爲什麼更改非const char *的分段錯誤?
char* inputStr = "abcde";
*(inputStr+1)='f';
如果代碼是:
const char* inputStr = "abcde";
*(inputStr+1)='f';
我會得到編譯錯誤「指定只讀位置」。 但是,對於第一種情況,沒有編譯錯誤;只是分配操作實際發生時的分段錯誤。
任何人都可以解釋這一點嗎?
這裏是什麼標準說,大約在部分字符串字面量[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
一旦轉換完成,你可以在語法上自由修改文字,但它會失敗,因爲編譯器存儲正如標準本身所允許的,它是一段不可寫的內存段。
儘管"abcde"
是一個字符串文本,不應該修改,但您已經告訴編譯器,您不關心這個問題,因爲非const char*
指向它。
編譯器會高興地認爲你知道你在做什麼,而不是拋出錯誤。但是,如果確實嘗試修改字符串文字,在運行時代碼很可能會失敗。
字符串文字通常存儲在只讀存儲器中。試圖改變這個記憶會殺死你的程序。
這裏有一個很好的解釋:Is a string literal in c++ created in static memory?
該標準規定,你不能直接修改字符串常量,不管你是否將它們標記const
與否:
是否所有的字符串文字是不同的(即存儲在不重疊的對象中)是實現定義的。試圖修改字符串文字的效果是未定義的。
事實上,在C(不像C++),字符串文字不const
但你還是不能給他們寫信。
上書寫,該限制允許一定的優化的發生,例如沿着線文字的共享:
char *ermsg = "invalid option";
char *okmsg = "valid option";
其中okmsg
實際上可以指向'v'
字在ermsg
,而不是一個明顯的串。
它主要是古代的歷史;曾經很久以前,字符串文字並不是一成不變的。但是,大多數現代編譯器將字符串文字放入只讀內存(通常是程序的文本段,代碼也位於此處),而任何嘗試更改字符串文字的操作都會產生核心轉儲或等效內容。
使用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]
$
所以警告默認啓用。
發生了什麼事是編譯器把常量"abcde"
在一些只讀內存段。你指出你的(非const)char* inputStr
在那個常數,KABOOM,段錯誤。要學習
經驗:不要調用未定義的行爲。
編輯(闡述)
但是,對於第一種情況,沒有編譯錯誤,只是分段錯誤的分配運算時實際發生的事情。
您需要啓用編譯器警告。始終將您的編譯器警告設置爲儘可能高。
字符串常量,而正式非const,幾乎總是存儲在只讀存儲器。在你的設置中,這顯然只是如果它被聲明爲const char數組的情況。
注意,標準禁止你修改任何文字字符串。
這得到代碼段創建:
char *a = "abcde";
本質上,它是常量。
如果您希望編輯它,嘗試:
char a[] = "abcde";
在裏奇的話字符串文字的歷史一點點。 主要是關於淵源考和字符串文字的給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
「
新的智能編譯器,像GCC,會警告你這一點。 – 2011-08-04 22:17:20