【问题标题】:Trying to split by two delimiters and it doesn't work - C试图用两个分隔符分割,但它不起作用 - C
【发布时间】:2009-11-13 03:45:11
【问题描述】:

我写了下面的代码,从标准输入中逐行读取。

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);
        }
}

【问题讨论】:

  • 你不是要取'del1'和'del2'的地址——它们已经是char *了。
  • 是的,你是对的,我重新输入错误

标签: c string split


【解决方案1】:

两点:第一,这条线不太好:

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

fgets() 总是以 '\0' 结束,这会产生奇怪的结果,因为您的输入未完全在 '\n' 结束。

其次,strtok() 不能同时调用两次。为此,请使用 strtok_r(),它接收一个 char** 作为第三个参数来存储状态。

【讨论】:

    【解决方案2】:

    看起来您需要使用 strtok 的可重入形式 strtok_r,因为当您在循环内调用 strtok 时,它会清除外部循环的字符串。当您调用 record = strtok(NULL) 时,它会再次尝试解析您的内部字符串。

    【讨论】:

      【解决方案3】:

      您不能使用 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 );
      

      所以你不需要&amp;del,因为del 已经是char *

      【讨论】:

        【解决方案4】:

        这是正在发生的事情:

        • 用户输入:a=1;b=2;c=3\n
        • fgets 之后:a=1;b=2;c=3\0
        • 第一次调用 strtok(non-NULL, ...)a=1\0b=2;c=3\0
        • 第二次调用 strtok(non-NULL, ...)a\01\0b=2;c=3\0

        strtok 在第一次使用非 NULL str 参数调用时会保留一些状态,因此它可以记住字符串的长度(或者,等效地,它在内存中的结束位置),因为它随后会破坏字符串,用 NULL 替换分隔符

        当您使用非 NULL 参数再次调用 strtok 时,保存状态的单个位置将被 strtok 认为是 3 个字符的新字符串覆盖和 NULL (a=1\0),因为 strtok 不能再记住原始输入特征。因此,record 在第一次迭代的循环结束时设置为 NULL,因为 strtok 认为它位于其(比预期短得多!)输入字符串的末尾.

        查看strtok_r

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-08
          • 1970-01-01
          • 2020-04-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-10
          相关资源
          最近更新 更多