2009-11-13 56 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