strtok
関数を説明する次のサンプルプログラムを見つけました。
_#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
_
ただし、これがどのように機能するかはわかりません。
pch = strtok (NULL, " ,.-");
が新しいトークンを返す可能性はありますか。つまり、strtok
with NULL
を呼び出しています。これは私にはあまり意味がありません。
strtok
について知っておくべき2つのこと。述べたように、それは「内部状態を維持する」。また、それはフィードする文字列を台無しにするです。基本的に、それは'\0'
を書き込み、指定したトークンを見つけて、文字列の先頭へのポインターを返します。内部的には、最後のトークンの場所を維持します。そして次にあなたがそれを呼ぶとき、それはそこから始まります。
重要な結果として、const char* "hello world";
文字列の内容を変更するとアクセス違反が発生するため、const char*
タイプの文字列ではstrtok
を使用できません。
strtok
の「良い」点は、実際には文字列をコピーしないことです。そのため、追加のメモリ割り当てなどを管理する必要はありません。ただし、上記を理解していないと、正しく使用できません。
例-「this、is、a、string」がある場合、strtok
を連続して呼び出すと、次のようにポインタが生成されます(^
は返される値です)。トークンが見つかった場所に'\0'
が追加されることに注意してください。つまり、ソース文字列が変更されます。
t h i s , i s , a , s t r i n g \0 this,is,a,string
t h i s \0 i s , a , s t r i n g \0 this
^
t h i s \0 i s \0 a , s t r i n g \0 is
^
t h i s \0 i s \0 a \0 s t r i n g \0 a
^
t h i s \0 i s \0 a \0 s t r i n g \0 string
^
それが理にかなっていると思います。
strtok
は内部状態を維持します。 NULL以外で呼び出すと、指定した文字列を使用するように再初期化されます。 NULL
で呼び出すと、その文字列と、現在次のトークンを返すために取得した他の状態が使用されます。
strtok
の動作方法により、マルチスレッドアプリケーションを作成している場合は、Cランタイムのマルチスレッドバージョンとリンクする必要があります。これにより、各スレッドがstrtok
の独自の内部状態を取得できるようになります。
strtok()
関数は、呼び出し間のデータを格納します。 NULLポインターで呼び出すときにそのデータを使用します。
From http://www.cplusplus.com/reference/cstring/strtok/ から:
最後のトークンが見つかったポイントは、次の呼び出しで使用される関数によって内部的に保持されます(特定のライブラリ実装は、データ競合を回避するために必要ありません)。
strtok
関数は、すべてのスレッド間で共有される内部静的変数にデータを格納します。
スレッドの安全性のために strtok_r
を使用する必要があります
から http://www.opensource.Apple.com/source/Libc/Libc-167/string.subproj/strtok.c
static char *last;
をご覧ください
char *
strtok(s, delim)
register char *s;
register const char *delim;
{
register char *spanp;
register int c, sc;
char *tok;
static char *last;
if (s == NULL && (s = last) == NULL)
return (NULL);
/*
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
if (c == 0) { /* no non-delimiter characters */
last = NULL;
return (NULL);
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
last = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}