2011-09-25 53 views
8

我試圖理解爲什麼下面的代碼是非法的一個字符:改變C字符串

int main() 
{ 
    char *c = "hello"; 
    c[3] = 'g'; // segmentation fault here 
    return 0; 
} 

,當它遇到char *c = "hello";什麼是編譯器做什麼?

我理解它的方式,它是一個char自動數組,而c是指向第一個char的指針。如果是這樣,c[3]就像*(c + 3),我應該能夠完成任務。

只是想了解編譯器的工作方式。

+2

**數組不是指針**和**指針不是數組**。字符串文字('「hello」')是一個由6個字符組成的數組(計數空終止符)。閱讀[comp.lang.c faq](http://c-faq.com/)的第6部分。一旦你完成了,請閱讀其他章節:) – pmg

+4

重複的太多,以列在這裏。 – 2011-09-25 19:28:21

+1

我們需要在SO問題代碼中引入一個過濾器,該代碼檢測'char * XX =「...」'並在那裏提供答案,然後在提問問題對話框中內聯。 –

回答

7

有這些之間的差:

char c[] = "hello"; 

char *c = "hello"; 

在第一種情況,編譯器在堆棧上爲6個字節(即5個字節用於「你好」,一個用於分配空間null終止符

在第二種情況下,編譯器在全局區域中生成一個名爲「hello」的靜態常量字符串(又名字符串文字,並在初始化爲指向該常量字符串的堆棧上分配一個指針。

你不能修改一個常量字符串,這就是爲什麼你得到一個段錯誤。

+0

在C語言中,字符串文字類型不是'const char [N]'('N'只夠大)。字符串文字確實有'char [N]'類型,但是改變它們是未定義的。 – pmg

+0

@pmg:我站着糾正 –

+0

你沒有收到一個正確的,因爲不是解決你的答案。他想要改變特定的字符,不改變其他結構,是的可能:) – delive

8

字符串常量是不可變的。即使您將它們分配到char *(因此將它們分配給const char *,以免忘記),也無法更改它們。

要進入一些細節,你的代碼大致相當於:

int main() { 
    static const char ___internal_string[] = "hello"; 
    char *c = (char *)___internal_string; 
    c[3] = 'g'; 
    return 0; 
} 

___internal_string通常分配給一個只讀的數據段 - 任何企圖改變有導致崩潰的數據(嚴格來說,其他結果也會發生 - 這是「未定義行爲」的一個例子)。但是,由於歷史原因,編譯器會讓您分配給char *,給您一個錯誤的印象,即您可以對其進行修改。

請注意,如果你這樣做,它的工作:

char c[] = "hello"; 
c[3] = 'g'; // ok 

這是因爲我們正在初始化非const字符數組。雖然語法看起來很相似,但編譯器會對它進行不同的處理。

+2

+1 for * approximate * ...但在C中,字符串文字類型不是const char [N](帶有「N」只是夠大)。字符串文字確實有'char [N]'類型,但是改變它們是未定義的。 – pmg

+0

我確實說過_roughly_等效:) – bdonlan

1

您不能更改字符串文字的內容。你需要複製一份。

#include <string.h> 

int main() 
{ 
    char *c = strdup("hello"); // Make a copy of "hello" 
    c[3] = 'g'; 
    free(c); 
    return 0; 
} 
+0

值得注意的是,使用其他海報建議的'char c []'可以減少錯誤發生的可能性,因爲您不需要釋放任何東西。 – Staven