x86/Debian GNU/Linux /gcc
strtok,strtok_r –从字符串中提取符号。
#include<string.h> char *strtok(char *str, const char *delim); char *strtok_r(char *str, const char *delim, char **saveptr); |
strtok()函数将某字符串解析成一序列的符号。第一次调用strtok()函数时,被解析的字符串需要放置在参数str中。后续调用strtok()来解析最初的字符串时,str需要被指定为NULL。
delim参数中指定的一套字符用来界定包含在被解析字符串中的符号。每当调用strtok()函数成功后,用户可以指定delim为不同的一套字符来解析(界定)最初指定的字符串str。
strtok()返回包含一个以空结束的符号。这个符号不包含界定字符。如果strtok()没再发现符号则返回NULL。
两个或毗邻方式排列的多个定界符序列在被解析字符串中都将被视为一个定界符。开始或者结尾的几个字节将会被忽视。换一种方式说:由strtok()函数的返回值通常都是非空的字符串。
strtok_r()函数是一个可重入函数。saveptr被strtok_r()用来维持解析相同字符串函数两次调用的上下文。
第一次调用strtok_r()函数时,str参数里应该保存需被解析的字符串,saveptr参数将会被忽略。在后续的调用中,str需要被指定为NULL,此时不能再改变saveptr的值。
不同的字符串需要被同时解析时,可以指明saveptr参数后连续调用strtok()_r来实现。
strtok()和strtok_r()函数返回指向下一个被分割到的字符串的地址。如果被分割完后返回NULL。
当用这些函数时需要注意:
这些函数将会修改它的第一个参数。
这些函数不能用于常量字符串(会修改它)。
定界符字符将会丢失。
当解析字符串时,strtok()函数用一个静态缓冲区,这表示此函数无线程安全性(threadsafe)。如果被这点困扰时就用strtok_r()函数。
以下程序用循环嵌套来调用strtok_r()来将一个字符串分割为两层结构的字符串。第一个命令行参数为被解析的字符串。第二个命令行参数指定定界符,这些定界符能够将第一个字符串分割为“major”符号(字符串)。第三个命令行参数指定被用来分割“major”符号成子符号的定界符。
程序源码strtok_r.c
#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; printf("%d: %s\n", j, token); for (str2 = token; ; str2 = NULL) { subtoken = strtok_r(str2, argv[3], &saveptr2); if (subtoken == NULL) break; printf(" --> %s\n", subtoken); } } exit(EXIT_SUCCESS); } |
编译并运行程序:
gcc -g strtok_r.c -o strtok_r ./strtok_r 'a/bbb///cc;xxx:yyy:' ':;' '/' 1:a/bbb///cc -->a -->bbb -->cc 2:xxx -->xxx 3:yyy -->yyy |
程序结果运行分析:
外层循环每次以第二个命令行参数':;'中的字符‘:'或';‘来解析目标字符串。第一次以';'得到符号a/bbb///cc,第二次以’:'得到符号xxx,第三次以’:'得到yyy。每次由strtok_r()函数返回的符号都不包含定界符':'或';‘。同理,内层循环以'/'来提取符号,分别得到a,bbb,cc;xxx;yyy。
用gdb单步运行来观察saveptr的值,截图一小段:
strtok_r()函数的saveptr参数中保存的是用来解析字符串的字串如':'的下一个字符,在此字符的前面会跟有一个数字是此字符的ASCII值。
文中,符号指的是被解析字符串经分隔符分割得到的子字符串。分隔符是delim字符串中的一个字符。用这两个函数时,都是使用delim中的一个字符去分割被解析字符串。被解析字符串指的是最初的str。
TNote Over.