2013-10-15 186 views
2

我知道const char *是一個指向const char的指針,而char *const是一個指向char的常量指針。 我在下面的代碼測試此:修改char * const字符串

const char *s = "hello"; // Not permitted to modify the string "hello" 
char *const t = "world"; // Not permitted to modify the pointer t 

s = "hello2"; // Valid 
// t = "world2"; // Invalid, gives compilation error 

// *(s + 1) = 'a'; // Invalid, gives compilation error 
*(t + 1) = 'a';  // Why does this not work?  

最後一行不給任何錯誤,但導致程序意外終止。爲什麼修改t指向的字符串不允許?

回答

7

t指向一個字符串字面這是不確定的行爲修改字符串字面。 C++標準牽伸部2.14.5字符串文字段落說重點礦山):

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

從C99標準草案中的相關部分是6.4.5字符串文字段落它說(重點礦山):

它是未指定的這些陣列是否是不同的提供它們的元素有 適當的值。 如果程序試圖修改這樣一個數組,行爲是 未定義。

在一個典型的現代Unix平臺上,你會發現字符串文字在只讀段,這將導致一個訪問衝突,如果我們試圖去修改它。我們可以使用objdump的如下檢查只讀部分:

objdump -s -j .rodata 

,我們可以在下面的live example看到字符串字面確實會在只讀部分找到。請注意,我必須添加printf否則編譯器會優化字符串文字。樣品`objdump的輸出:

Contents of section .rodata: 
400668 01000200 776f726c 64002573 0a00  ....world.%s.. 

另一種方法是將有t指向數組,象這樣的字符串字面副本:

char r[] = "world";  
char *const t = r ; 
+1

你說出了標準,但你並沒有真正說出爲什麼(程序如何)會因爲錯誤而終止......只是說... Elchonon Edelson給出了實際的原因,我認爲這是正確的答案。 –

+0

@AlexisWilke該標準意味着與平臺無關,這些細節依賴於平臺,這就是爲什麼標準使用諸如未定義行爲之類的語言來涵蓋整個範圍的行爲,包括正常工作但不能依賴的行爲。我爲典型的現代unix平臺添加了更多細節。 –

3

雖然在C字符串文字正式具有類型char[](陣列的char,不const)的,C標準明確規定,他們必須爲不可修改的處理。編譯器傾向於將字符串文字放在只讀段中,因此嘗試修改它們會導致訪問衝突。

字符串文字在C11標準(ISO/IEC 9899:2011)的6.4.5部分中描述。

1

您可以繞過編譯器錯誤,重寫爲char*,如*((char*)s + 1) = 'a';,但由於它已在其他答案中被確定,這是未定義的行爲,並且可能會導致分段錯誤,因爲您正在編輯字符串文字。

1

如果您想正確測試它,請在函數中初始化字符串,以便初始化可以是動態的,並使用strdup()

int 
main(int argc, char **argv) 
{ 
    char *d1 = strdup("hello"); 
    char *d2 = strdup("world"); 

    const char *s = d1; 
    char *const t = d2; 

    ... 

    free(d1); 
    free(d2); 
} 

D1和D2變量主要用於使得動態分配可以在端部利用free()被正確釋放。另外,正如其他答案所示,始終將字符串文字視爲const char *