2017-07-13 4 views
0

J'ai une chaîne qui ressemble à 1,3-5,7,9-11 et je dois le marquer avec des appels répétés à strtok de sorte que la sortie ressemble à quelque chose comme:strtok dans les boucles imbriquées se comporte de manière inattendue

1 
3 
5 
7 
9 
11 

Mon code ressemble à ceci:

#include <stdio.h> 
#include <string.h> 

void tokenize(char *string){ 
    char *token; 
    token = strtok (string,"-"); 
    while (token != NULL) { 
      // ... do some other unrelated stuff ... 
      printf("\tToken %s\n", token); 
      token = strtok (NULL, ","); 
    } 
} 

int main (int argc,char **argv) 
{ 
    char *token; 
    token = strtok (*(argv+1),","); 
    while (token != NULL) { 
      if (strchr(token,45)){ //45 is ASCII for "-". 
        tokenize(token); 
      } 
      printf("Token1 %s \n", token); 
      token = strtok (NULL, ","); 
    } 
    return 0; 
} 

Cependant, quand je lance le code se termine prématurément et je reçois:

./tokenizer 1,3-5,7,9-11 
Token1 1 
     Token 3 
     Token 5 
Token1 3 

mais je pense/veulent quelque chose comme:

./tokenizer 1,3-5,7,9-11 
Token1 1 
     Token 3 
     Token 5 
Token1 7 
     Token 9 
     Token 11 

Si je commente la ligne qui lit tokenize(temptoken); (en d'autres termes, strtok sur « » seulement), la sortie ressemble on peut s'y attendre:

./tokenizer 1,3-5,7,9-11 
Token1 1 
Token1 3-5 
Token1 7 
Token1 9-11 

il semble donc que le problème est vraiment avec les appels ultérieurs à strtok la chaîne déjà tokenized alors j'ai essayé de memcpy mémoire pointé le pointeur symbolique, mais cela n'aide pas vraiment:

#include <stdio.h> 
#include <string.h> 

void tokenize(char *string){ 
    char *token; 
    token = strtok (string,"-"); 
    while (token != NULL) { 

      printf("\tToken %s\n", token); 
      token = strtok (NULL, ","); 
    } 
} 

int main (int argc,char **argv) 
{ 
    char *token; 
    char *temptoken ; 
    token = strtok (*(argv+1),","); 
    while (token != NULL) { 
      if (strchr(token,45)){ //45 is ASCII for "-". 
/* added memcpy */ memcpy(temptoken,token,strlen(token)+1); 
        tokenize(temptoken); 
      } 
      printf("Token1 %s \n", token); 
      token = strtok (NULL, ","); 
    } 
    return 0; 
} 


$ ./tokenizer 1,3-5,7,9-11 
Token1 1 
     Token 3 
     Token 5 
Token1 3-5 

Des idées de ce que je peux faire pour réparer le code, comprendre où se situe mon malentendu, et obtenir le résultat souhaité?

+1

vous 'memcpy' ** nulle part ** ...' temptoken' est un pointeur non initialisé. Et puis, pour les chaînes, utilisez juste 'strcpy' à la place (une fois que vous avez correctement alloué de la mémoire pour votre cible). –

+2

utilise 'strtok_r',' strtok' a un effet secondaire intégré. –

+0

Oui, vous avez raison, mais j'ai supposé que les programmeurs C++ seraient également capables de répondre à la question. –

Répondre

5

Vous ne pouvez pas utiliser strtok() imbriqué car il utilise de la mémoire statique pour enregistrer son contexte entre les invocations afin de connaître la position actuelle dans la chaîne en cours de segmentation. À la place, utilisez strtok_r(), qui est une version réentrante de strtok qui n'a aucun état interne.

+1

Oui et juste en répétant pour l'OP (et d'autres) que 'strtok' est une fonction de bibliothèque plutôt ancienne - ne vous sentez pas mal d'être dérouté par son comportement conçu, vous n'êtes pas le premier. Personne ne conçoit plus de fonctions de bibliothèque/API comme celle-ci! –

-1
while (token != NULL) { 
     if (strchr(token,45)){ //45 is ASCII for "-". 
     /* added memcpy */ memcpy(temptoken,token,strlen(token)+1); 
       tokenize(temptoken); 
     } 
     printf("Token1 %s \n", token); 
     token = strtok (NULL, ","); 
} 

Et qu'attendez-vous.

vous trouvez le jeton « » tokenize alors avec votre fonction (et imprimer les jetons) vous imprimer ce jeton avant la subtokenisation à nouveau et il se termine comme strtok a un état interne.

Donc, cela fonctionne exactement comme vous l'avez écrit.

vous devez: utiliser la version rentrante od strtok,

vous devez retourner la valeur dans votre fonction tokenize pour indiquer si subtokens ont été trouvés: sinon imprimer le jeton, si oui, non.