2009-11-13 36 views
3

我寫下面的代碼從stdin ex逐行讀入。試圖由兩個分隔符分裂,它不起作用 - C

city=Boston;city=New York;city=Chicago\n 

然後用';'分隔每一行。分隔並打印每條記錄。 然後在另一個循環中,我嘗試按'='分隔符分割記錄以獲得實際值。但出於某種原因,主(第一)循環不會循環超出第一次迭代,爲什麼?

char* del1 = ";"; 
char* del2 = "="; 
char input[BUFLEN]; 

while(fgets(input, BUFLEN, fp)) { 

     input[strlen(input)-1]='\0'; 
     char* record = strtok(input, &del1); 

     while(record) { 
       printf("Record: %s\n",record); 

       char* field = strtok(record, &del2); 
       while(field) { 
        printf("Field: %s\n",field); 
        field = strtok(NULL, &del2); 
       } 

       record = strtok(NULL, &del1); 
     } 
} 
+0

你不是要取'del1'和'del2'的地址 - 它們已經是char *了。 – pilcrow 2009-11-13 03:55:09

+0

是的,你說得對,我錯誤地重新輸入了 – goe 2009-11-13 04:02:00

回答

3

兩件事情:第一,這條線不太好:

input[strlen(input)-1]='\0'; 

與fgets()總是以「\ 0」結束,並恰好在「您的輸入還沒有完成這會給怪異的結果\ N」。

其次,strtok()不能同時調用兩次。爲此,使用strtok_r(),它接受char **作爲第三個參數來存儲狀態。

+0

謝謝,這對我很好。 – goe 2009-11-13 04:15:07

1

你不能使用兩個循環的strtok,因爲strtok會在你的字符串中存儲全局指針。

你將不得不做一個循環來分開;,存儲這些結果和一個循環,以將=分隔到先前存儲的結果上。

char* del1 = ";"; 
char* del2 = "="; 
char input[BUFLEN]; 
char* tokens[255]; // have to be careful not to go more then that 
while(fgets(input, BUFLEN, fp)) { 

    // input[strlen(input)-1]='\0'; // you don't need that fgets add the NULL 
    char* record = strtok(input, del1); 
    i = 0; 
    while(record) { 

      tokens[i++] = strdup(record); 
      record = strtok(NULL, del1); 
    } 
    for(v = 0; v < i; v++){ 
     char* field = strtok(token[v], del2); 
     while(field) { 
      printf("Record: %s\n",token[v]); 
      printf("Field: %s\n",field); 
      field = strtok(NULL, del2); 
     } 
    } 
} 

請注意,您必須free所有的strdup字符串後,或者你要創建一個內存泄漏。

也請沒有的strtok簽名

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

,所以你不需要&del因爲德爾已經是一個char *

2

看起來您需要使用strtok的可重入窗體strtok_r,因爲當您在循環內調用strtok時,它將擦除外部循環的字符串。當你調用record = strtok(NULL)時,它試圖再次解析你的內部字符串。

+0

strtok_r()...在Windows上還有strtok_s()。 – asveikau 2009-11-13 04:06:20

1

這裏是正在發生的事情:與fgetsa=1;b=2;c=3\n

  • a=1;b=2;c=3\0
  • 第一個呼叫到的strtok(非NULL,...)

    • 用戶輸入a=1\0b=2;c=3\0
    • 第二次致電strtok(非NULL,...)a\01\0b=2;c=3\0

    的strtok保持一個位狀態,當它首先與非空STR參數調用,因此它可以記住該字符串多久(或等效地,在存儲器中它的結束位置),因爲此後它會損壞字符串,用空值替換分​​隔符。

    當您再次調用的strtok與非空的說法,但如狀態保持改寫什麼的strtok察覺單一的地方是3個字符的新字符串和NULL(a=1\0),因爲strtok不能再記住原始輸入特徵。因此,記錄在第一次迭代的循環結束時設置爲NULL,因爲strtok認爲它處於其(比預期更短!)輸入字符串的末尾。

    結賬strtok_r

  • +0

    很好的解釋。 – jheddings 2009-11-13 04:12:38