#include <string.h> char *strtok(char *str, const char *delim); char *strtok_r(char *str, const char *delim, char **saveptr);
glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):
strtok_r():
_POSIX_C_SOURCE
|| /* Glibc versions <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE
delim 引数には、解析対象の文字列をトークンに区切るのに使用する バイト集合を指定する。同じ文字列を解析する一連の呼び出しにおいて、 delim に違う文字列を指定してもよい。
strtok() のそれぞれの呼び出しでは、次のトークンを格納したヌル終端 された文字列へのポインターが返される。この文字列には区切りバイトは含まれ ない。これ以上トークンが見つからなかった場合には、NULL が返される。
同じ文字列に対して操作を行う strtok() を連続して呼び出す場合、 次のトークンを探し始める位置を決めるためのポインターが保持される。 最初の strtok の呼び出しでは、 このポインターは対象の文字列の最初のバイトにセットされる。 次のトークンの先頭は、 str 内で次の区切りバイト以外のバイトを前方に検索して決定される。 区切りバイト以外のバイトが見つからなかった場合は、 トークンはこれ以上なく、 strtok() は NULL を返す (したがって、 空の文字列や区切りバイトだけを含む文字列の場合には、 最初の strtok() の呼び出しで NULL が返ることになる)。
各トークンの末尾は、次の区切りバイトが見つかるか、終端のヌルバイト ('\0') に達するまで文字列を前方に検索することで見つかる。 区切りバイトが見つかった場合には、 現在のトークンの終わりを示すために、 見つかった区切りバイトがヌルバイトで上書きされ、 strtok() はポインターを次のバイトに設定する。 このポインターは、次のトークンを検索する際の開始点として使用される。 この場合、 strtok() は見つかったトークンの先頭へのポインターを返す。
上記の説明の通り、 解析対象の文字列に 2 つ以上の区切りバイトが連続している場合には、 一つの区切りバイトとみなされ、 文字列の先頭や末尾にある区切りバイトは無視される。 言い換えると、 strtok() が返すトークンは必ず空でない文字列となる。 したがって、例えば "aaa;;bbb," という文字列が与えられたとすると、 区切り文字列 ";," を指定した一連の strtok() の呼び出しでは、 "aaa" と bbb" が返り、その次にヌルポインターが返る。
The strtok_r() function is a reentrant version of strtok(). The saveptr argument is a pointer to a char * variable that is used internally by strtok_r() in order to maintain context between successive calls that parse the same string.
On the first call to strtok_r(), str should point to the string to be parsed, and the value of *saveptr is ignored (but see NOTES). In subsequent calls, str should be NULL, and saveptr (and the buffer that it points to) should be unchanged since the previous call.
strtok_r() の呼び出し時に異なる saveptr 引数を指定することで、 異なる文字列の解析を同時に行うことができる。
インターフェース | 属性 | 値 |
strtok() | Thread safety | MT-Unsafe race:strtok |
strtok_r() | Thread safety | MT-Safe |
このプログラムの出力例を以下に示す。
$ ./a.out 'a/bbb///cc;xxx:yyy:' ':;' '/'
1: a/bbb///cc
--> a
--> bbb
--> cc
2: xxx
--> xxx
3: yyy
--> yyy
int
main(int argc, char *argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelim\n",
argv[0]);
exit(EXIT_FAILURE);
}
for (int 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);
}
strtok() を使った別のプログラム例が getaddrinfo_a(3) にある。