该函数strtok使用一组定界符将字符串分成较小的字符串或标记。
#include <stdio.h> #include <string.h> int main(void) { int toknum = 0; char src[] = "Hello,, world!"; const char delimiters[] = ", !"; char *token = strtok(src, delimiters); while (token != NULL) { printf("%d: [%s]\n", ++toknum, token); token = strtok(NULL, delimiters); } /* source is now "Hello\0, world\0\0" */ }
输出:
1: [Hello] 2: [world]
分隔符字符串可以包含一个或多个分隔符,并且对的每次调用都可以使用不同的分隔符字符串strtok。
调用以strtok继续标记相同的源字符串不应再次传递源字符串,而应NULL作为第一个参数传递。如果传递了相同的源字符串,则第一个标记将被重新标记。也就是说,给定相同的定界符,它们strtok将再次简单地再次返回第一个令牌。
请注意,由于strtok不会为令牌分配新的内存,因此会修改源字符串。也就是说,在以上示例中,将对字符串src进行操作以生成由调用所返回的指针所引用的令牌strtok。这意味着源字符串不能是const(因此它不能是字符串文字)。这也意味着分隔字节的标识丢失了(即,在示例中,“,”和“!”已从源字符串中有效删除,并且您无法确定匹配了哪个分隔符)。
另请注意,源字符串中的多个连续定界符被视为1;在示例中,第二个逗号被忽略。
strtok既不是线程安全的也不是重入线程,因为它在解析时使用静态缓冲区。这意味着如果一个函数调用strtok,它在使用时所调用的函数也不能strtok使用strtok,并且它本身不能使用的任何函数都不能调用它strtok。
一个示例说明了由于strtok未重入而引起的问题,如下所示:
char src[] = "1.2,3.5,4.2"; char *first = strtok(src, ","); do { char *part; /* Nested calls to strtok do not work as desired */ printf("[%s]\n", first); part = strtok(first, "."); while (part != NULL) { printf(" [%s]\n", part); part = strtok(NULL, "."); } } while ((first = strtok(NULL, ",")) != NULL);
输出:
[1.2] [1] [2]
预期的操作是外do while循环应该创建三个令牌由每个十进制数串的("1.2","3.5","4.2"),对于每一个中,strtok用于内循环调用应该它分成单独的数字串("1","2","3","5","4","2")。
但是,由于strtok不是可重入的,因此不会发生这种情况。相反,第一个strtok正确地创建了“ 1.2 \ 0”令牌,而内部循环正确地创建了令牌"1"和"2"。但是strtok,外循环中的in在内循环使用的字符串的末尾,并立即返回NULL。src完全不分析数组的第二和第三子字符串。
标准C库不包含线程安全或可重入版本,而其他一些库(例如POSIX')包含strtok_r。请注意,在MSVC上,strtok等效项strtok_s是线程安全的。
C11有一个可选部分,附件K,提供了名为的线程安全和可重入版本strtok_s。您可以使用来测试功能__STDC_LIB_EXT1__。此可选部分不受广泛支持。
该strtok_s功能与POSIX功能的不同之处在于,它可以strtok_r防止存储在要标记化的字符串之外,并可以检查运行时约束。在正确编写的程序上,strtok_s和的strtok_r行为相同。
strtok_s现在,与示例一起使用可产生正确的响应,如下所示:
/* you have to announce that you want to use Annex K */ #define __STDC_WANT_LIB_EXT1__ 1 #include <string.h> #ifndef __STDC_LIB_EXT1__ # error "we need strtok_s from Annex K" #endif char src[] = "1.2,3.5,4.2"; char *next = NULL; char *first = strtok_s(src, ",", &next); do { char *part; char *posn; printf("[%s]\n", first); part = strtok_s(first, ".", &posn); while (part != NULL) { printf(" [%s]\n", part); part = strtok_s(NULL, ".", &posn); } } while ((first = strtok_s(NULL, ",", &next)) != NULL);
输出将是:
[1.2] [1] [2] [3.5] [3] [5] [4.2] [4] [2]