2013-01-22 110 views
4

我對C字符串聲明中的一些基本知識感到困惑。我嘗試了下面的代碼,我注意到一些差異:C字符串聲明

char* foo(){ 
    char* str1="string"; 
    char str2[7]="string"; 
    char* str3=(char)malloc(sizeof(char)*7); 
    return str1; 
    /* OR: return str2; */ 
    /* OR: return str3; */ 
    } 
void main() { 
    printf("%s",foo()); 
    return 0; 
    } 

我提出FOO()的返回STR1/2/3一次一個,並試圖打印結果在主。 str2返回了一些奇怪的東西,但str1和str3返回了實際的「字符串」。

1.現在這三個聲明有什麼區別?我認爲str2之所以不起作用是因爲它被聲明爲局部變量,這是否正確?

2.那麼str1呢?如果結果在foo()結束後仍然存在,是不是會導致內存泄漏?

3.我只是試圖編寫一個函數,它返回C中的一個字符串,並將該函數返回的值用於其他的東西,我應該使用哪個str聲明?

在此先感謝!

回答

8
char* str1="string"; 

這使得str1是一個指針;它指向字符串文字的第一個字符。你應該把它定義爲const,因爲你不允許修改字符串文字:

const char *str1 = "string"; 

...

char str2[7]="string"; 

這使得str2char數組(不是指針),和將字符串文字的內容複製到其中。沒有必要將其定義爲const;該陣列本身是可寫的。還可以省略尺寸,讓它通過初始化來確定:

char str2[] = "string"; 

然後sizeof str2 == 7(6個字節爲"string"加1用於終止'\0')。

此:

char* str3=(char)malloc(sizeof(char)*7); 

編寫不當,它甚至不應該編譯;至少,你應該從你的編譯器得到警告。您正在將malloc()的結果轉換爲char。你應該將其轉換爲char*

char *str3 = (char*)malloc(sizeof(char) * 7); 

但投是不必要的,可以掩蓋在某些情況下的錯誤;參見問題7.7和在comp.lang.c FAQ如下:

char *str3 = malloc(sizeof(char) * 7); 

sizeof(char)是1的定義,所以你可以這樣寫:

char *str3 = malloc(7); 

malloc()分配內存,但它並沒有初始化,所以如果您嘗試打印str3指向的字符串,如果分配的空間不包含終止空字符'\0',則會得到垃圾 - 甚至是運行時崩潰。你可以用strcpy()初始化它,例如:

char *str3 = malloc(7); 
if (str3 == NULL) { 
    fprintf(stderr, "malloc failed\n"); 
    exit(EXIT_FAILURE); 
} 
strcpy(str3, "string"); 

你必須要非常小心,你複製的數據是不超過所分配的空間更大。 (否,`strncpy() is not the answer to this problem。)

void main()不正確;它應該是int main(void)。如果你的教科書告訴你使用void main()找到更好的教科書;它的作者不太瞭解C.

而你需要爲你使用任何庫函數適當#include指令:<stdio.h>printf()<stdlib.h>exit()malloc(),並<string.h>strcpy()。每個函數的文檔都應該告訴你要包含哪個頭文件。

我知道這是很多吸收;不要指望馬上理解它。

我提到了comp.lang.c FAQ;這是一個很好的資源,特別是第6節,討論數組和指針以及它們之間經常令人困惑的關係。如果你的問題3,如何從C函數返回一個字符串,事實證明,由於C內存分配的方式(基本上它自己管理它),結果會非常複雜。你不能安全地返回一個指向局部變量的指針,因爲當函數返回時該變量不再存在,使得調用者留下一個懸掛指針,因此返回str2是危險的。返回一個字符串文字是可以的,因爲它對應於整個執行程序時存在的匿名數組。你可以用static聲明一個數組並返回一個指針,或者你可以使用malloc()(這是最靈活的方法,但它意味着調用者需要free()內存),或者你可以要求調用者傳入一個指針到你的函數將複製結果的緩衝區。

有些語言讓你建立一個字符串值,並簡單地從函數中返回它。正如你現在發現的那樣,C不是這些語言之一。

+0

感謝您的澄清。在這種情況下,如果我的函數必須返回一個任意長度的字符串,我在函數中使用了一個char [someLength]緩衝區,我怎樣才能返回這個緩衝區作爲輸出? – turtlesoup

+0

@ user1926344:首先,請注意您的「任意長度」字符串不能長於「someLength」字節。其次,你只需將它複製到調用者可以訪問的某個內存區域 - 這意味着你可以直接跳過'char [someLength]'變量並將其複製到那裏。該區域可以是'靜態'(有一些缺點),或者它可以是'malloc()',也可以由調用者來分配它並將函數傳遞給指針。 –

6
char* str1="string"; 

這將創建一個指向將位於任.data.text段和在任何時候都可以訪問的文本字符串。每當你做這樣的事情時,一定要聲明它const,因爲如果你嘗試修改它,可能會發生討厭的事情。

char str2[7]="string"; 

這會在堆棧上創建一個本地緩衝區,並帶有文本字符串的副本。一旦函數返回,它就變得不可用。這解釋了你得到的奇怪結果。

char* str3=(char)malloc(sizeof(char)*7); 

這會在堆(未初始化)上創建一個緩衝區,直到您釋放它爲止。並且釋放它你必須,否則你會得到內存泄漏。

0

字符串文字"string"存儲爲char 7個元素的數組的靜態程度,這意味着它的內存在程序啓動時分配並保持到該程序終止。

聲明

char *str1 = "string"; 

分配地址字符串文本str1。即使變量str1在函數退出時不再存在,其(文字"string"的地址)在該函數之外仍然有效。

聲明

char str2[7] = "string"; 

聲明str2作爲char陣列,並複製內容的字符串文字到它的。當函數退出時,str2不復存在,其內容不再有意義。

聲明

char *str3 = (char*) malloc(sizeof(char) * 7); 

這可以簡化爲

char *str3 = malloc(sizeof *str3 * 7); 

分配存儲器並複製其地址未初始化的7字節的塊str3。當函數退出時,變量str3不再存在,但它指向的內存仍被分配。正如所寫,這內存泄漏,因爲你不保留調用代碼中指針的值。請注意,由於您不會將任何內容複製到此塊,因此main中的輸出將是隨機的。

而且,除非你的編譯器的文檔明確名單void main()作爲main功能的合法簽名,使用int main(void)代替。