2013-11-04 49 views
1

我有一個非常非常簡單的功能,給我一些問題。我想要做的就是在從字符串中更改後返回一個子字符串。但是當我運行代碼時,我有分段錯誤。什麼是我的代碼發生的事情:函數返回字符串不工作 - 分段錯誤

#include <stdio.h> 
#include <string.h> 

const char *new_name(char str[]) 
{ 

    char * pch; 
    char * last=""; 
    char * pch2; 
    static char name[80]; 
    printf ("Splitting string \"%s\" into tokens:\n",str); 

    pch = strtok (str,"/"); 
    while (pch != NULL) 
    { 
    last=pch; 
    pch = strtok (NULL, "/"); 

    } 

    pch2 = strtok (last,"."); 
    strcpy(name, pch2); 
    strcat(name, ".ppm"); 

    return name; 
} 

int main() 
{ 
    printf("New name: %s",new_name("/home/test/segmentation/test.pgm")); 
    return 0; 

} 

編輯:我還有一個問題:我想用這個功能作爲輸入另一個函數的返回,但它接受char和返回值是爲const char。如何進行轉換?

+0

這裏使用的strtok似乎矯枉過正,用一個簡單的循環由年底'字符* CH循環找到最後/; for(ch = str + strlen(str) - 1; ch!='/'; --ch);'現在ch指向'/',因爲您沒有修改參數。 –

回答

2

strtok將修改它的第一個參數,所以你不能一個指針傳遞給一個字串它會調用未定義的行爲。

更改前兩行的main這樣:

char str[] = "/home/test/segmentation/test.pgm"; 
printf("New name: %s\n",new_name(str)); 
2

您必須記住strtok函數修改了的字符串輸入。並且您將它傳遞給一個文字字符串的指針,它是常量(即只讀)。嘗試修改文字字符串會導致未定義的行爲。

的解決方案是很簡單:

char str[] = "..."; 
printf("New name: %s\n", new_name(str)); 
1

strtok第一個參數不能是常量字串(這正是一個字符串文字是):

pch = strtok (str,"/"); 
       ^^^ 

因爲它修改其第一個參數,鏈接文件說:

char * strtok(char * restrict str,const char * restrict delim);

該函數具有破壞性:它將'\ 0'字符寫入字符串str的元素中。特別是,字符串文字不能用作strtok的第一個參數。

使用非const的陣列將解決此問題:

char arr[] = "/home/test/segmentation/test.pgm" ; 
printf("New name: %s",newname(arr)); 

爲了完整起見,修改字符串文字undefined behavior在節中的C99草案標準6.4.5字符串文字段落說(重點煤礦):

未指定這些數組是否不同,只要它們的元素具有 適當的值。 如果程序試圖修改這樣一個數組,行爲是 undefined

+0

@glglgl我意識到'它'是什麼意思,這是一個錯字。 –

+0

沒有違法意圖。我經常在這裏看到這個錯誤... – glglgl

2

strtok通過改變它傳遞的字符串來工作。您無法將常量字符串傳遞給strtok

您可以嘗試

char str[] = "/home/test/segmentation/test.pgm"; 
printf("New name: %s",new_name(str)); 

代替。

3

事故發生在strtok。問題是你傳遞一個指向字符串的指針作爲它的第一個參數,而字符串文本通常在只讀內存中,所以strtok在嘗試更改字符串時會崩潰。

char *strtok(char *str, const char *delim); 

人去修補方式:

char fileName[] = "/home/test/segmentation/test.pgm"; 
printf("New name: %s",new_name(fileName)); 

編輯:回答下面 '編輯' 你的問題。

只要改變你的函數的簽名,返回char *

char *new_name(char str[]) 

然而,這將是很好的去改變它多一點。代替使用本地靜態緩衝區(name),最好將緩衝區作爲第二個參數傳遞,並在客戶端代碼中調用函數之前分配它。這種方法的問題是,通常調用者不知道要生成的字符串的確切長度或甚至最大長度。

另一個也許更好的選擇是分配緩衝區的內存,使用malloc動態返回並返回指向調用者的指針。在這種情況下,釋放緩衝區的責任將與用戶代碼一起進行,因此您應該正確記錄它。

+0

你能看到我的編輯嗎? – mad

+0

@mad不是真的。它是什麼? – piokuc

+0

我想用函數的返回值作爲char,所以它可以作爲另一個函數的輸入。怎麼做? – mad

1

new_name("/home/test/segmentation/test.pgm")

你傳入一個字符串(只讀),並strtok正在修改這個字符串