2012-11-12 287 views
0

我開始學習C,並且我不明白我做錯了什麼。這裏是一個函數的簡單代碼,它返回pid +「。data」。返回一個字符串指針

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

char * getfilename(){ 
    char name[60]; 
    sprintf(name,"%i.data",getpid()); 
    return name; 
} 

void main(){ 
    char* name = getfilename(); 
    printf("%s",name); 
} 

輸出:��#�a

所以我想我做錯了什麼。

+1

你應該用'gcc -Wall -g'編譯得到所有的警告和調試信息。海灣合作委員會會警告你。然後,您可能希望使用'gdb'來調試問題,一旦您改進了代碼,直至不給出警告爲止。 –

回答

4
char * getfilename(){ 
    char name[60]; 
    sprintf(name,"%i.data",getpid()); 
    return name; 
} 

getfilename返回後,您將無法訪問name對象。自動對象name的使用期限終止於getfilename末尾}。函數返回後訪問它是未定義的行爲。

作爲臨時修復,您可以指定namestatic,它將起作用。但是你應該做的就是讓getfilename函數接受一個指向參數的地方,在這個地方寫文件名。

編輯:

爲什麼我不建議使用strdup

  • strdup不是標準C函數。 strdup住在POSIX世界。出於便攜性的原因,我會盡可能使用標準C函數。
  • strdup執行隱藏的malloc調用,並且您不必忘記執行free。這與從未呼叫malloc(或實際上從未出現致電malloc)的標準C庫的所有功能相反。 strdup是一個糟糕的API設計。
  • strdup正在執行字符串的副本。爲什麼你需要執行一個額外的副本?只需將字符串寫入可以檢索它的位置即可。
1
char name[60] 

生活在棧中,但只只要是內部getfilename()之後的釋放,所以任何引用(如也getfilename()返回)將其變爲無效。

1

char name[60]是一個局部變量,它在函數調用時被分配,當它返回時被釋放。當你試圖返回它時,你真的返回它的地址(畢竟所有的數組大部分都是用於指針算術的語法糖)。現在,你的調用者有一個指向已被釋放的內存塊的指針,因此可能包含垃圾。

3

一種解決方案是使用strdup,即改變:

return name; 

到:

return strdup(name); 

這使得使用動態內存分配的臨時(本地)字符串的一個副本(即malloc)。

當然,你必須確保你隨後使用free這個字符串。

你需要:

#include <string.h> // strdup() 
#include <stdlib.h> // free() 
+0

如果包含相關頭文件,我會+1。 – jpm

+0

@jpm:確定 - 完成。 –

1

你不能從你的函數getfilename數組name返回,因爲它是一個(普通)局部變量和那些得到清理功能returnes時。 因此,當您回到main並嘗試打印返回的值時,指針name指的是一塊已被重新用於其他目的的內存塊。

有幾種方案來解決這個問題:

  1. getfilenamestaticname。這將確保它的呼叫超過getfilename的呼叫並且可以安全地返回,但是具有所有對getfilename的呼叫使用相同緩衝器的缺點。
  2. malloc動態分配的數組(不要忘了free把它清理乾淨,當你用它做)
  3. 傳遞給存儲作爲參數值的緩衝區。
+0

最好的答案之一。一個問題,在getfilename的調用中使用相同的緩衝區會出現什麼問題? –

+0

在這種特殊情況下,沒有問題。但想象這個代碼'char * one = getfilename(); char * two = getfilename();''getfilename'可以在每次調用時用不同的內容填充緩衝區。 –

0

正如在其他答案中提到的,你不能返回指向函數堆棧某處的指針。

您可以簡單地將分配的數組傳遞給getfilename()函數。您可以按如下方式重寫程序。

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

void getfilename(char * name) 
{ 

    sprintf(name,"%i.data",getpid()); 
} 

int main(void) 
{ 
    char name[60]; 
    getfilename(name); 
    printf("%s\n",name); 
    return 0; 
} 

這應該很好。