2013-07-02 58 views
3

比方說,我有以下規格的函數:C中的字符串參數是否動態分配?

void example(char* str) 

如果我傳遞一個字符串參數,如:

example("testing"); 

是「測試」的值動態地分配在堆上,所以我可以在調用「example」的函數調用的作用域被銷燬(並且稍後需要釋放它)之後使用它,或者它是堆棧中的局部變量,所以我需要使一個使用malloc的新字符串,並將值存儲在那裏,如果我希望它保存在一個hashmap中?

謝謝。

+0

[是靜態內存中創建的C++中的字符串字面值?](http://stackoverflow.com/questions/349025/is-a-string-literal-in-c-created-in-static-內存) – paddy

+0

@paddy - 儘管類似的名字,C和C++是不同的野獸。但你是正確的,肯定有這個重複。 – mouviciel

+1

嗯,我記得在過去回答這個問題,但無法列出[我的答案](http://stackoverflow.com/questions/14468697/where-is-memory-allocated-with-a-const-char-pointer/14468729#14468729)作爲重複,因爲問題隨後被關閉並標記爲重複。相反,我列出* that * duplicate,這恰好用C++來表達。 – paddy

回答

8

當您在程序中編寫"testing"時,它將被編譯爲字符串文字,並且會在編譯期間爲其分配空間。當你得到一個指向它的指針時,它是指向內存中的那個地方的指針。你不需要用malloc()來分配它,你也不應該把它分配給free()它。但是嘗試修改其內容也不是一個好主意,因爲編譯器可能會將其置於只讀區域(即它被編譯爲常量) - 例如,以下程序在我的Linux桌面上崩潰:

#include <stdio.h> 
int main() { 
    char *a = "abc\n"; 
    a[0]='X'; 
    printf(a); 
    return(0); 
} 
1

最常見的情況是,它將作爲字符串文字存儲在可執行文件的只讀部分。實際上,您可以通過用-S標誌編譯程序來手動驗證。

它將生成一個名爲name_of_your_app.s的程序集可執行文件,其中可以找到字符串文字(它將位於所謂的data segment中)。

有時編譯器可以放入代碼段或取決於優化級別,它將簡單地優化它(最容易通過創建一個字符串文字來檢查,該文本不會在任何地方使用,然後使用GCC上的-O3標誌進行編譯)。

這裏的(人爲)例如:

int main() 
{ 
    char *a = "Hai!"; 

    return 0; 
} 

如果我沒有特殊標誌的字符串文字編譯它仍然存在:

$ gcc -S main.c 
main.c: In function ‘main’: 
main.c:9:11: warning: unused variable ‘a’ [-Wunused-variable] 
$ cat main.s | grep Hai 
    .string "Hai!" 

但是,一旦我殺青的優化級別,它不再是這種情況:

$ gcc -S -O3 main.c 
main.c: In function ‘main’: 
main.c:9:11: warning: unused variable ‘a’ [-Wunused-variable] 
$ cat main.s | grep Hai 
$ 

它看起來像this answer解決相同的問題。

+0

不能保證它將以只讀方式存儲,儘管這是一個常見的實現。 –

+0

感謝您的評論,我想偶爾可以在代碼段找到它,或者由編譯器進行優化。我會爲我的答案添加更新。 – Nobilis

+0

或者它可以存儲在讀/寫存儲器中。嘗試修改字符串文字有未定義的行爲,所以它*可以*「工作」,具體取決於實現。 –

3

在C中,引號之間的字符串「such as this」被稱爲字符串文字

字符串文字(如上面給出的內容)不會動態分配。通常,它們在編譯和/或鏈接時被分配,並且可以被分配在只讀存儲器中。 (這就是爲什麼,在C++,字符串是const char而非char。)

引擎蓋下,一些編譯器藏匿在一個字符串表「測試」,產生一個特殊的指針。這大致相當於這個:

char *const compiler_generated_pointer_to_testing = (char *) (compiler_generated_string_table + 12345); 

... 

const char compiler_generated_string_table[] = { 
    ... 
    't', 'e', 's', 't', 'i', 'n', 'g', 0, 
    ... 
}; 

... 

example(compiler_generated_pointer_to_testing); 

這是它可以發揮出來的一種方式。許多其他實現是合法的。在任何情況下,實現細節可能都是重點。要記住真正的要點是:

  • 編譯時字符串文字應被視爲const,即使編譯器不要求你指針作爲const char *宣佈他們。
  • 它們在編譯和/或鏈接時分配,而不是在堆或堆棧上分配。
  • 相同字符串的兩個實例(即程序不同部分中的foo("testing")bar("testing"))不保證是不同的指針,也不保證它們是相同的指針值。
  • 您絕對不能使用free()字符串。
  • 您絕不能寫入字符串文字。
  • 字符串文字在程序的整個生命週期中保持可用,所以它可以正常工作,例如散列鍵。

明白了嗎?任何問題?

+2

FWIW,在C語言中,字符串文字不是'const char'的唯一真正原因是C最初沒有以這種方式定義它們。當「const正確性」獲得蒸汽作爲編程範例時,C語言具有重要的安裝基礎,如果字符串文字追溯爲「const」,則該基礎將會中斷。 C++沒有這個負擔。 如果你真的想用你的代碼加皮帶和大括號,儘可能的聲明你的指針'const'。用他自己的話來說,John Carmack已經成了一個「常規」納粹分子:http://www.phoronix.com/scan.php?page=news_item&px=MTI3NDQ –