Toc toc token
Par Jean-Seb le vendredi 1 mai 2009, 20:38 - Coding - Lien permanent
Un billet sur la fonction strtok...
... avec en prime une petite devinette.
man strtok
définition très personnelle du token
- La première fois que l'on m'a parlé du token, je me suis bien demandé ce que c'était.
- Une définition courte et lapidaire serait:
- un token est un élément indivisible.
- Je tente donc de préciser quelque peu:
- un token est un élément atomique d'un surensemble.
- par exemple: dans une phrase, on admet généralement que le mot est l'élément atomique (on ne descend pas au caractère).
- la notion de token suppose celle de séparateur, pour différencier les token du surensemble.
strtok dans la bibliothèque standard
- strtok : fonction de la bibliothèque
string.h. Elle extrait des token d'une chaine.
strtok (char *chaine, char *separateurs)
- une invocation singulière
- le premier appel de strtok doit comporter un pointeur sur la chaine à découper en token.
- les appels suivant à strtok doivent comporter un pointeur NULL en lieu et place de la chaine à découper.
char *chaine="ceci;est;une;chaine''; char *token = strtok(chaine,";"); //premier appel while (token = strtok(NULL,";"); //appels suivant
La devinette
- Maintenant que vous savez tout sur les token, voici la devinette.
- Ce source provoque un core-dump sous Linux.
#include <stdio.h>
#include <string.h>
char * get_token(char *string, char *sep)
{
static char *token = 0;
if (token) string=NULL;
token = strtok (string, "sep");
return token;
}
int main(void)
{
char *token = 0;
while (token=get_token("ceci;est;une;chaine",";")) {
printf("token = %s\n",token);
}
return 0;
}
strace est ton ami
chaine littérale et strtok
- Tout réside dans l'appel de la fonction get_token.
- Le paramètre passé à cette fonction est une chaine définie à la compilation (une chaine littérale).
- Cette chaine est donc placée dans un segment read-only.
- Sans même débugger, on peut le vérifier avec un strace qui indiquera la violation mémoire lors de l'appel à strtok :
gcc -Wall -W token_test.c && strace ./a.out- mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7dde000
résolution
- Il ne faut donc jamais passer de chaines
en dur
dans votre code à strtok.- Il faut soit recopier la chaine dans la fonction d'arrivée, soit passer un pointeur sur un buffer contenant votre chaine.
- Attention! Passer un pointeur sur une chaine définie à la compilation
provoquera également un plantage.
char *chaine="ceci;est;une;chaine";: core-dumpchar chaine[]="ceci;est;une;chaine";: ok , car ce n'est pas une chaine littérale, mais une liste d'initialisation de tableau ( (c) Fred. J. )
- Encore une chose: strtok modifie la chaine source passée en paramètre. En voici la preuve:
#include <stdio.h>
#include <string.h>
int main(void)
{
char chaine[]="ma;chaine";
printf("origine: %s\n",chaine);
strtok(chaine,";");
for (int i=0; i<sizeof(chaine); i++)
printf("[0x%X]%c ",chaine[i],chaine[i]);
return 0;
}
- Ce programme donne en sortie:
/tmp$ ./a.out origine: ma;chaine [0x6D]m [0x61]a [0x0] [0x63]c [0x68]h [0x61]a [0x69]i [0x6E]n [0x65]e [0x0]
- Notez que le point-virgule a été remplacé par la valeur zéro, ce qui risque de donner des résultats assez comiques si vous réutilisez le buffer par la suite.
Et tok.
- A noter qu'aux dernières nouvelles, MS-Windows ne passait pas ses chaines
dans un segment en lecture seule.
- Encore un bon exemple des pièges qui attendent les courageux adeptes du multiplateforme.
- On peut certe remplacer courageux par les fous qui font tout en C.
- La libc, c'est la bonne humeur au quotidien. Alors mangez-en, et parlez-en à vos amis.