C 字符串标记化问题

C 字符串标记化问题,c,string,tokenize,C,String,Tokenize,我有这个字符串:“阿拉斯加:(3,4)”,我想要“阿拉斯加”,“3”,“4”子字符串。但我有个问题 cityName = strtok(str , ":"); printf("name : %s\n",cityName); temp = strtok(NULL , "("); printf("%s\n",temp); temp = strtok(NULL , ","); printf("%s\n",temp); temp = strtok(NULL, ")"); printf("%s\n",te

我有这个字符串:
“阿拉斯加:(3,4)”
,我想要
“阿拉斯加”
“3”
“4”
子字符串。但我有个问题

cityName = strtok(str , ":");
printf("name : %s\n",cityName);
temp = strtok(NULL , "(");
printf("%s\n",temp);
temp = strtok(NULL , ",");
printf("%s\n",temp);
temp = strtok(NULL, ")");
printf("%s\n",temp);
对于此代码,我得到以下输出:

name : Alaska
3,4)
(null)
(null)

怎么了?

实现不起作用的原因是
strtok
在第二次调用后将字符串识别为已完全解析(因为在第一个标记之前未找到任何内容)。您需要在第二次调用后重新启动解析

void bar(char * str) {
    char * cityName, *temp;
    cityName = strtok(str , ":");
    printf("name : %s\n",cityName);
    temp = strtok(NULL , "(");
    printf("%s\n",temp);
    temp = strtok(temp , ","); // restart parsing here
    printf("%s\n",temp);
    temp = strtok(NULL, ")");
    printf("%s\n",temp);
}
请注意,
strtok
对输入字符串具有破坏性,并且不是线程安全的

您是否考虑过使用
sscanf
系列?如果你有固定的格式,使用起来会容易一些

void foo(char * str) {
    char city[32], num[2][32];
    sscanf(str, "%[^:]:(%[^,],%[^)])", city, num[0], num[1]);
    printf("%s\n%s\n%s\n", city, num[0], num[1]);
}

请看一下strtok的文档:

对strtok函数的一系列调用将s1指向的字符串分解为 标记序列,每个标记由指向的字符串中的一个字符分隔 由s2。序列中的第一个调用具有非空的第一个参数;中的后续调用 序列的第一个参数为空。s2指向的分隔符字符串可能是 不同的呼叫不同。
序列中的第一个调用在s1指向的字符串中搜索第一个字符 s2指向的当前分隔符字符串中不包含的。如果没有这样的性格 则s1和strtok函数指向的字符串中没有令牌 返回空指针。如果找到这样的字符,则它是第一个标记的开始。
然后strtok函数从那里搜索包含在 当前分隔符字符串。如果未找到此类字符,则当前标记将扩展到 s1指向的字符串的结尾,随后对令牌的搜索将返回null 指针。如果找到这样一个字符,它将被一个空字符覆盖,该空字符 终止当前令牌。strtok函数保存指向以下内容的指针 字符,将从其开始下一次标记搜索

简而言之,
strtok
搜索序列开头的第一个不在分隔符中的字符,然后搜索序列结尾的分隔符中的第一个字符。
这意味着您对strtok的最后两次调用返回
NULL
,因此
printf
-调用是未定义的行为,任何事情都可能发生

最好使用
sscanf
或使用自己的解析器(可能不再需要)

如果要继续使用strtok,请更正分隔符,并仅尝试获取三个令牌:

cityName = strtok(str , ":");
printf("name : %s\n",cityName);
temp = strtok(NULL , "(,)");
printf("%s\n",temp);
temp = strtok(NULL , "(,)");
printf("%s\n",temp);

仍然至少考虑移动到<代码> Sttokks以避免数据竞争,使代码重新进入。< > P> <代码> Sttok(3)< /C>不喜欢空分隔符。你有权访问吗


这是如何回答这个问题的?+1第一次,这个问题清楚地说明了问题、给出的代码、输入、输出和期望的输出。可悲的是,这是罕见的。
char str[] = "Alaska:(3,4)";
char *p = str;
char *temp;
char *cityName = strsep(&p , ":");
printf("name : %s\n",cityName);
temp = strsep(&p , "(");
printf("%s\n",temp);
temp = strsep(&p , ",");
printf("%s\n",temp);
temp = strsep(&p, ")");
printf("%s\n",temp);