J'ai trouvé cet exemple de programme qui explique la fonction 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;
}
Cependant, je ne vois pas comment cela peut fonctionner.
Comment est-il possible que pch = strtok (NULL, " ,.-");
renvoie un nouveau jeton. Je veux dire, nous appelons strtok
with NULL
. Cela n'a pas beaucoup de sens pour moi.
Deux choses à savoir sur strtok
. Comme cela a été mentionné, il "maintient l'état interne". En outre, il gâche la chaîne que vous l'alimentez. Essentiellement, il écrira un '\0'
où il trouve le jeton que vous avez fourni et renvoie un pointeur au début de la chaîne. En interne, il conserve l'emplacement du dernier jeton; et la prochaine fois que vous l'appelez, cela commence à partir de là.
Le corollaire important est que vous ne pouvez pas utiliser strtok
sur un const char* "hello world";
type de chaîne, car vous obtiendrez une violation d'accès lorsque vous modifierez le contenu d'un const char*
chaîne.
La "bonne" chose à propos de strtok
est qu'elle ne copie pas réellement les chaînes - vous n'avez donc pas besoin de gérer l'allocation de mémoire supplémentaire, etc. Mais à moins de comprendre ce qui précède, vous aurez du mal à l'utiliser correctement.
Exemple - si vous avez "this, is, a, string", les appels successifs à strtok
généreront des pointeurs comme suit (le ^
est la valeur renvoyée). Notez que le '\0'
est ajouté là où se trouvent les jetons; cela signifie que la chaîne source est modifiée:
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
^
J'espère que cela a du sens.
strtok
maintient l'état interne. Lorsque vous l'appelez avec une valeur non NULL, il se réinitialise pour utiliser la chaîne que vous fournissez. Lorsque vous l'appelez avec NULL
, il utilise cette chaîne et tout autre état doit actuellement renvoyer le jeton suivant.
En raison de la façon dont strtok
fonctionne, vous devez vous assurer que vous établissez une liaison avec une version multithread du runtime C si vous écrivez une application multithread. Cela garantira que chaque thread obtiendra son propre état interne pour strtok
.
La fonction strtok()
stocke les données entre les appels. Il utilise ces données lorsque vous l'appelez avec un pointeur NULL.
De http://www.cplusplus.com/reference/cstring/strtok/ :
Le point où le dernier jeton a été trouvé est conservé en interne par la fonction à utiliser lors du prochain appel (des implémentations de bibliothèque particulières ne sont pas requises pour éviter les courses de données).
La fonction strtok
stocke les données dans une variable statique interne qui est partagée entre tous les threads.
Pour la sécurité des fils, vous devez utiliser strtok_r
De http://www.opensource.Apple.com/source/Libc/Libc-167/string.subproj/strtok.c
Jetez un oeil à 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 */
}