NAME
strtok, strtok_r从字符串中提取符号组
概要
#include <string.h>
char *strtok(char *str, const char *delim);
char *strtok_r(char *str, const char *delim, char **saveptr);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
strtok_r(): _POSIX_C_SOURCE
|| /*Glibc versions <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE
描述
strtok()函数将一个字符串分割成一系列非空的字符组。第一次调用strtok,要parse的字符串由str指定。后面每次调用strtok就是parse同一个字符串,str必须是NULL。delim参数确定一组字节,这组字节用于分割字符串中的符号组。在后面的调用的时候,strtok可以指定不同的delim来分割字符串。
每次调用strtok,strtok都返回一个指向包含下一个tokens,以null结尾的字符串。这个字符串不包括定界字节。如果没有找到跟多的字符组,strtok返回NULL。
一系列的操作在同一个字符串上的strtok调用,维护了一个指向下一次要搜索符号组的开始位置的指针。第一次调用strtok把指针指向字符串的第一个字节。下一个符号组的开始位置是通过向前扫描下一个非delim字符。如果找到这样的一个字节,这就作为下一个符号组的开始位置。如果没有找到这样的字节,那就是没有更多的字符了。strtok就返回NULL。(因此,如果一个字符串是空的或者只包括了定界符那么它就会在第一次调用的时候返回NULL)。
字符组的最后一个字节是通过扫描到下一个定界符或者是Null终止符。如果一个定界符被找到了,那么它就被一个null byte重写来终止当前的符号组。strtok会保存下个一个字节的位置到一个指针,这个指针会作为搜索下一个符号组的开始位置。strtok会返回指向已经找到的那个符号组的指针。
从上面的描述上看,字符串中一系列连续的分隔符会被当作一个分隔符。并且开头或者末尾的分界符会被忽略。换句话说,strtok返回的符号组一定是非空字符串。因此比如给定字符串“aaa;;bbb”,连续调用将“;”作为定界符的strtok会返回字符串“aaa”和“bbb”,然后是一个null指针。
strtok_str是strtok的可重入版本。saveptr参数是一个指向char*变量的指针。这个指针是strtok_r内部用来维护parse的那个字符串的。
第一次调用strtok_r,str应该指向要parse的那个字符串。saveptr的值被忽略了。在后面的调用的时候,str应该是NULL,saveptr应该保持不变。
不同的字符串可能并行的被指定不同的saveptr参数的strtok_r序列parse。
返回值
strtok和strtok_r函数返回一个指向字符组的指针,或者Null。
属性
这部分使用的属于的详细解释,请查看attribute(7)。
Interface | Attribute | Value |
strtok() | Thread safety | MT-unsafe race:strtok |
strtok_r() | Thread saf |
规范
strtok()
POSIX.1-2001, POSIX.1-2008, C89, C99, SVr4, 4.3BSD
strtok_r()
POSIX.1-2001, POSIX.1-2008
Bugs
使用这些函数的时候要小心。如果你用它们那么注意:
- 这些函数会修改它们的第一个参数。
- 这些函数不能被用在constant字符串上面。
- 定界符字节会丢失
- strtok()函数会使用一个用来parse的静态buffer,所以它是线程不安全的,如果这个影响到你,那么请使用strtok_r()函数。
例子
下列程序在一个嵌套循环中使用了strtok_r(),它把一个字符串分割成两级符号组。第一个命令行参数确定要解析的字符串。第二个参数确定分割符字节将字符串分割成“major”字符组。第三个参数确定定界字节将“major”字符组,分割成子字符组。
这个程序产生的输出的一个例子如下:
$ ./a.out 'a/bbb///cc;xxx:yyy:' ':;' '/'
1: a/bbb///cc
--> a
--> bbb
--> cc
2: xxx
--> xxx
3: yyy
--> yyy
源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char* argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
int j;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelim\n",
argv[0]);
exit(EXIT_FAILURE);
}
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, argv[2], &saveptr1);
if (token == NULL) {
break;
}
for(str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, argv[3], &saveptr2);
if (subtoken == NULL)
break;
printf(" --> %s\n", subtoken);
}
}
exit(EXIT_SUCCESS);
}
另一个使用strtok的例子可以在getaddrinfo_a(3)里面找到。
参考
index(3), memchr(3), rindex(3), strchr(3), string(3), strpbrk(3), strsep(3), strspn(3), strstr(3), wcstok(3)
版权页标记
本页是4.15 Linux man-pages项目的一部分。关于这个项目的描述、报bug相关信息,以及本页的最新版本可以在https://www.kernel.org/doc/man-pages/找到。
GNU 2017-09-15 STRTOK(3)