我找到了这个解释strtok
函数的示例程序:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
但是,我不知道这是如何工作的。
pch = strtok (NULL, " ,.-");
如何返回新令牌?我的意思是,我们使用strtok
致电NULL
。这对我来说没有多大意义。
答案 0 :(得分:36)
有关strtok
的两件事情。如前所述,它“保持内部状态”。此外,它弄乱你喂它的字符串。从本质上讲,它会在找到您提供的令牌时写入'\0'
,并返回指向字符串开头的指针。在内部,它维护最后一个令牌的位置;下次你打电话给它,就从那里开始。
重要的推论是,您无法在strtok
类型的字符串上使用const char* "hello world";
,因为修改const char*
字符串的内容时会出现访问冲突。
strtok
的“好”之处在于它实际上并不复制字符串 - 所以你不需要管理额外的内存分配等。但除非你理解上述内容,否则你将无法使用它正确。
示例 - 如果你有“this,is,a,string”,对strtok
的连续调用将生成如下指针(^
是返回的值)。请注意,'\0'
会添加到找到令牌的位置;这意味着修改了源字符串:
t h i s , i s , a , s t r i n g \0 this,is,a,string
t h i s \0 i s , a , s t r i n g \0 this
^
t h i s \0 i s \0 a , s t r i n g \0 is
^
t h i s \0 i s \0 a \0 s t r i n g \0 a
^
t h i s \0 i s \0 a \0 s t r i n g \0 string
^
希望它有意义。
答案 1 :(得分:2)
strtok
维持内部状态。当您使用非NULL调用它时,它会重新初始化自己以使用您提供的字符串。当你用NULL
调用它时,它会使用该字符串,以及当前获得的任何其他状态返回下一个标记。
由于strtok
的工作方式,如果您正在编写多线程应用程序,则需要确保链接到C运行时的多线程版本。这将确保每个线程获得strtok
的内部状态。
答案 2 :(得分:2)
strtok()
函数在调用之间存储数据。当您使用NULL指针调用它时,它会使用该数据。
来自http://www.cplusplus.com/reference/cstring/strtok/:
找到最后一个标记的点由内部保留,用于下次调用时使用的函数(不需要特定的库实现来避免数据争用)。
答案 3 :(得分:0)
strtok
函数将数据存储在一个内部静态变量中,该变量在所有线程之间共享。
对于线程安全,您应该使用strtok_r
来自http://www.opensource.apple.com/source/Libc/Libc-167/string.subproj/strtok.c
看看static char *last;
char *
strtok(s, delim)
register char *s;
register const char *delim;
{
register char *spanp;
register int c, sc;
char *tok;
static char *last;
if (s == NULL && (s = last) == NULL)
return (NULL);
/*
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
if (c == 0) { /* no non-delimiter characters */
last = NULL;
return (NULL);
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
last = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}