2013-10-31 58 views
1

我被困在一件相當平凡的事情中...... 所以,基本上我想要第一個和最後一個之間的「單詞」去數據和最後一個去鍵。從字符串獲得元素

僅C-POSIX,請。

strtok_r是要走的路嗎,還是我在這方面呢?還有別的嗎?

char *key = NULL, *data=NULL, *save=NULL; 
char comando[1024]; 
fgets(comando, 512, stdin); 

strtok_r(comando, " ",&save); 

while(strcmp(save,"\n")){ 
    strcat(data,strtok_r(NULL," ",&save)); 
} 

key = strtok_r(NULL, "\n",&save); 

P.S:comando是1024作爲內存不是問題,並且比抱歉更安全。 fgets讀取512',因爲這是標準unix終端上的字符行限制。

+0

您是否嘗試過調試?也許會打印一些輸出,比如每次調用'strtok_r()'後''指向'' – gnobal

+0

'我認爲使用'strtok_r'沒問題......或者是什麼地方出錯了? – PhillipD

+0

您需要爲'data'和'key'分配內存。現在你正在附加一個空指針。 –

回答

1

您的代碼會崩潰在這條線:

strcat(data,strtok_r(NULL," ",&save)); 

因爲你從不爲data預留了空間。 strcat會嘗試寫入一個NULL內存地址。

還有一點需要注意的是,您不應該依賴save來檢查行的末尾。根據strtok的手冊頁:

的saveptr參數是一個指向一個char *變量由strtok_r使用0​​內部(),以保持該解析相同的字符串 連續調用之間的上下文。

依託saveptrstrtok_r斷抽象層的價值,你不應該承擔有關如何strtok使用saveptr什麼。這是不好的做法。

稍好一點的方法是保留一個指向由strtok返回的前一個標記的指針,以及一個指向當前標記的指針。當strtok返回NULL時,意味着沒有更多的標記,那麼prev將指向最後一個標記,即您的key。下面是一些代碼:我被聲明爲數組,而不是指針分配空間data

char *key = NULL, *save=NULL; 
char *prev, *curr; 
char comando[1024]; 
char data[1024]; 

data[0] = '\0'; 
fgets(comando, 512, stdin); 
prev = curr = strtok_r(comando, " ",&save); 

while (curr != NULL) { 
    prev = curr; 
    curr = strtok_r(NULL, " ", &save); 
    if (curr != NULL) 
     strcat(data, prev); 
} 

key = prev; 

注意。該指令

data[0] = '\0'; 

有確保strcat發現在第一次調用空終止字節。

您可以直接替換prev的使用key,我讓它使代碼更具可讀性。

一個忠告:永遠記住strtok破壞性地修改它的參數(你失去了分隔字節的身份),並且你不能用常量字符串調用它。

注意:data將包含每個單詞連接。你失去了空間。我不確定這是不是你想要的。如果不是,你可能想要使用比strcat更好的東西(這不是非常高效,順便說一下)。例如,您使用sprintf代碼使用前導空格將令牌打印到data,並將指針指向data中的下一個空閒位置。

1

我建議用下面的代碼來替換你的循環(printf()的使用只是用於測試):

strtok_r(comando, " ", &save); 
char *res = NULL; 
while (NULL != (res = strtok_r(NULL, " ", &save))) { 
    if (key != NULL) { 
    //strcat(data, key); // FIXME 
    printf("data = %s\n", key); 
    } 
    key = res; 
} 
printf("key = %s\n", key); 

另外的strcat()不應該與NULL參數一起使用 - 它會導致崩潰。所以數據指針應該指向某個數組。代碼的運行結果:

┌─(16:08:22)─([email protected])─(~/tmp/strtok) 
└─► gcc -o main main.c; echo "one two three four five" | ./main 
data=two 
data=three 
data=four 
key = five 
1

很多你的代碼錯誤

char *key = NULL, *data=NULL, *save=NULL; 

後來,你正在使用strcat添加字符串data而你卻沒有分配存儲,以data。這會導致分段錯誤。

fgets(comando, 512, stdin); 

fgets會讀比傳遞給它的數量最多一個都不能少。所以,如果用戶輸入了512個字符,則字符串將不會終止\n。此外,檢測錯誤或文件結束的唯一方法是檢查返回結果fgets。如果它是NULL,或者您已達到文件結尾(用戶已按ctrl-d)或出現錯誤。無論哪種情況,緩衝區的內容都是不確定的。

while(strcmp(save,"\n")) 

我不認爲你被允許依賴於你的save指針將指向未消耗的字符串的其餘部分的假設。

strtok_r(comando, " ",&save); 

strtok_r信號,它已經通過返回NULL指針到達數據的末尾。如果不看它,你不能丟棄返回結果。此外,這將消耗尾部\n作爲最後一個令牌的一部分。

strcat(data,strtok_r(NULL," ",&save)); 

正如我前面所說的,data是一個空指針。此外,strtok_r可以返回NULL

我會做更多的東西一樣:

char* currentTok = strtok_r(commando, " \n", &save); // separator is space or \n 
char* previousTok = NULL; 
while (currentTok != NULL) 
{ 
    if (previousTok != NULL) 
    { 
     // save previousTok in data unless its the first token 
    } 
    previousTok = currentTok; 
    currentTok = strtok_r(NULL, " \n", &save); 
} 
char* key = previousTok;