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)