2009-11-13 2 views
3

J'ai écrit ci-dessous le code à lire ligne par ligne depuis stdin ex.Essayer de diviser par deux délimiteurs et cela ne fonctionne pas - C

city=Boston;city=New York;city=Chicago\n 

puis diviser chaque ligne par ';' délimiter et imprimer chaque enregistrement. Ensuite, dans une autre boucle, j'essaie de diviser l'enregistrement par le délimiteur '=' pour obtenir les valeurs réelles. Mais pour une raison quelconque, la boucle (principale) principale ne boucle pas au-delà de la première itération, pourquoi?

char* del1 = ";"; 
char* del2 = "="; 
char input[BUFLEN]; 

while(fgets(input, BUFLEN, fp)) { 

     input[strlen(input)-1]='\0'; 
     char* record = strtok(input, &del1); 

     while(record) { 
       printf("Record: %s\n",record); 

       char* field = strtok(record, &del2); 
       while(field) { 
        printf("Field: %s\n",field); 
        field = strtok(NULL, &del2); 
       } 

       record = strtok(NULL, &del1); 
     } 
} 
+0

Vous ne voulez pas prendre l'adresse de 'del1' et 'del2' - ils sont déjà char *. – pilcrow

+0

oui vous avez raison, je l'ai retapé incorrectement – goe

Répondre

3

Deux choses: d'abord, cette ligne n'est pas très bon:

input[strlen(input)-1]='\0'; 

fgets() termine toujours avec « \ 0 » et cela donnera des résultats étranges avec votre entrée n'est pas terminé exactement à « \ n '.

Deuxièmement, strtok() ne peut pas être appelé deux fois simultanément. Pour cela, utilisez strtok_r(), qui reçoit un char ** comme troisième argument pour stocker l'état.

+0

Merci, cela a bien fonctionné pour moi. – goe

1

Vous ne pouvez pas utiliser deux boucles de strtok car le strtok stocke globalement le pointeur dans votre chaîne.

Vous auriez à faire une boucle pour séparer le ;, stocker ces résultats et une boucle pour séparer le = sur le résultat précédemment enregistré.

char* del1 = ";"; 
char* del2 = "="; 
char input[BUFLEN]; 
char* tokens[255]; // have to be careful not to go more then that 
while(fgets(input, BUFLEN, fp)) { 

    // input[strlen(input)-1]='\0'; // you don't need that fgets add the NULL 
    char* record = strtok(input, del1); 
    i = 0; 
    while(record) { 

      tokens[i++] = strdup(record); 
      record = strtok(NULL, del1); 
    } 
    for(v = 0; v < i; v++){ 
     char* field = strtok(token[v], del2); 
     while(field) { 
      printf("Record: %s\n",token[v]); 
      printf("Field: %s\n",field); 
      field = strtok(NULL, del2); 
     } 
    } 
} 

vous s'il vous plaît noter devez free toutes les chaînes strdup après ou vous allez créer une fuite de mémoire.

aussi s'il vous plaît pas la signature de strtok est

char * strtok (char * str, const char * delimiters); 

de sorte que vous n'avez pas besoin &del depuis del est déjà un char *.

2

On dirait que vous devez utiliser la forme re-entrant de strtok, strtok_r car lorsque vous appelez strtok à l'intérieur de votre boucle, il efface la chaîne pour la boucle extérieure. Lorsque vous appelez record = strtok (NULL), il essaie d'analyser à nouveau votre chaîne interne.

+0

+1 pour strtok_r() ... il y a aussi strtok_s() sur Windows. – asveikau

1

Voici ce qui se passe:

    entrée utilisateur
  • : a=1;b=2;c=3\n
  • après fgets: a=1;b=2;c=3\0
  • 1er appel à strtok (non NULL, ...): a=1\0b=2;c=3\0
  • 2ème appel à strtok (non-NULL, ...): a\01\0b=2;c=3\0

strtok garde un peu d'état quand il est d'abord invoqué avec un non-NULL l'argument str, il peut donc se rappeler combien de temps la chaîne était (ou, ce qui revient, où la mémoire se termine), car il écrase la chaîne par la suite, en remplaçant les délimiteurs par des valeurs NULL.

Lorsque vous appelez strtok à nouveau avec un argument non NULL, ce lieu unique où l'état est maintenu est remplacée par ce que strtok perçoit comme une nouvelle chaîne de 3 caractères et un NULL (a=1\0), depuis strtok ne peut plus se souvenir des caractéristiques d'entrée d'origine. Donc, enregistrement est défini à NULL à la fin de la boucle à la première itération, car strtok pense qu'il est à la fin de sa chaîne d'entrée (beaucoup plus courte que prévu!).

Découvrez strtok_r.

+0

Bonne explication. – jheddings

Questions connexes