在C语言中使用strtok()函数对字符串进行两次分词

9

我在C语言中使用strtok()函数来解析CSV字符串。首先,我将其标记化以仅查找有多少个标记,以便我可以分配正确大小的字符串。然后,我使用与上次标记化相同的变量进行遍历。但是,每次第二次这样做时,strtok(NULL, ",")返回NULL,即使还有更多的标记需要解析。请问有人能告诉我我做错了什么吗?

char* tok;
int count = 0;
tok = strtok(buffer, ",");
while(tok != NULL) {
    count++;
    tok = strtok(NULL, ",");
}

//allocate array

tok = strtok(buffer, ",");
while(tok != NULL) {
    //do other stuff
    tok = strtok(NULL, ",");
}

在第二个 while 循环中,即使有更多的 token,它总是在找到第一个 token 后结束。有人知道我做错了什么吗?


2
现在似乎每个人都知道strtok()是什么,但没有人读过文档?我学习C语言的时候也没人告诉我它,但是当我必须要使用它的时候,我立刻去仔细阅读了相关文档。 - Karl Knechtel
3个回答

19

strtok() 修改它所操作的字符串,将分隔符字符替换为 null。因此,如果你想多次使用它,你必须要先复制一份。


2

通常情况下,并不需要复制字符串 - strtok() 会修改被分词的字符串,但在大多数情况下,这意味着如果你想再次处理令牌,则该字符串已经被分词。

下面是稍作修改以便在第一遍处理后处理令牌的程序:

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

int main()
{
    int i;
    char buffer[] = "some, string with  ,  tokens";

    char* tok;
    int count = 0;
    tok = strtok(buffer, ",");
    while(tok != NULL) {
        count++;
        tok = strtok(NULL, ",");
    }


    // walk through the tokenized buffer again
    tok = buffer;

    for (i = 0; i < count; ++i) {
        printf( "token %d: \"%s\"\n", i+1, tok);
        tok += strlen(tok) + 1;  // get the next token by skipping past the '\0'
        tok += strspn(tok, ","); //   then skipping any starting delimiters
    }

     return 0;
  }

请注意,这比我最初发布的要棘手得多 - 对strspn()的调用需要在跳过strtok()放置的'\0'之后执行,因为strtok()将跳过任何前导分隔符字符以返回它返回的令牌(而不替换源中的分隔符字符)。


另一种方法是将第一遍的令牌指针存储在数组中。当然,这意味着需要有最大数量的令牌或动态数组。但这也可以行得通。 - Fred Larson

2
使用strsep - 它实际上会更新你的指针。在您的情况下,您将不得不不断调用NULL而不是传递您字符串的地址。 strsep唯一的问题是如果它之前分配在堆上,请保留指向开头的指针,然后稍后释放它。
char *strsep(char ** string,char * delim);
char *string; char *token; token = strsep(&string,“,”);
strtok在您正常的C课程介绍中使用 - 使用strsep,它更好。 :-) 不会因为“该死 - strtok搞砸了我的位置”,而感到困惑。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接