2017-06-27 1 views
-1

Je lis les enregistrements d'un fichier CSV en utilisant fgets() pour lire le fichier une ligne à la fois, et strtok() pour analyser les champs de chaque ligne. Je rencontre un problème où fgets() écrase une chaîne qui a été précédemment écrite, en faveur de la nouvelle chaîne.
Voici un exemple de ce que je veux dire par là:
Les chaînes stockées précédemment sont remplacées par des fgets

record.csv (Ceci est le fichier que je lis dans)

John,18 
Johann,29 

main.c

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

typedef struct customer { 
    char *name; 
    int age; 
} Customer; 

int main(void) 
{ 
    FILE *csv_data; 
    char line[100], *token; 
    Customer newData[2]; 

    csv_data = fopen("record.csv", "r"); 
    // Index 0 for John's data, index 1 for Johann's data 
    int i = 0; 

    /* loops until end of file */ 
    while(fgets(line, 100, csv_data)) { 

     /* name field */ 
     token = strtok(line, ","); 
     if (token != NULL) { 
      newData[i].name = token;   
     } 

     /* age field */ 
     token = strtok(NULL, ","); 
     if (token != NULL) { 
      // atoi() converts ascii char to integer 
      newData[i].age = atoi(token); 
     } 
     i++; 
    } 
    /* print John's records */ 
    printf("%s\n", newData[0].name); 
    printf("%d\n", newData[0].age); 

    /* print Johann's records */ 
    printf("%s\n", newData[1].name); 
    printf("%d\n", newData[1].age); 

    return 0; 
} 


Lorsque nous compilons et exécutons ceci, il imprime:

Johann 
18 
Johann 
29 

"John" dans newData[0].name est remplacé par "Johann" lors de la deuxième itération de la boucle while. Notez cependant que seules les chaînes sont mélangées, mais pas les entiers. Je suppose que cela a à voir avec fgets parce que quand j'ai modifié la source ci-dessus pour exécuter seulement fgets une fois, la sortie pour "John" était comme il se doit. Peut-être que j'utilise abusivement fgets (ou peut-être mon hypothèse est erronée), mais quelqu'un pourrait-il me donner des indications sur la raison pour laquelle les chaînes sont remplacées avec chaque appel à fgets?

Deuxième mise à jour: Merci encore beaucoup à tous les commentateurs et les répondeurs. Bon à savoir ces choses dont je n'étais pas au courant. La source fonctionne parfaitement maintenant.

+3

Vous copiez chaque ligne sur la même variable 'line'; vous ne faites pas de copie des données trouvées par 'strtok'. Voilà comment l'écrasement se produit. Allouer de l'espace et copier les données, en utilisant peut-être 'strdup()'. C ne gère pas la mémoire pour les chaînes pour vous; vous devez le faire pour vous-même. –

+0

@xing, ohh, la mémoire de 'newData [i] .name' doit-elle être allouée manuellement dans le tas? Je n'étais pas au courant de ça. Merci, je vais essayer. @JonathanLeffler so 'newData [i] .name = token' ne copie pas les données? – ctatton

+1

vous pouvez allouer de la mémoire pour le nom en changeant ceci: 'newData [i] .name = token;' à ceci: 'newData [i] .name = strdup (token);'. – bruceg

Répondre

1

Vous ne copiez pas la chaîne mais le pointeur sur la chaîne.

Une manière très simple de copier la chaîne, mais notez que cela limite la taille de la chaîne à 99 caractères.

typedef struct customer { 
    char name[100]; 
    int age; 
} Customer; 

strcpy(newData[i].name, token); 
1

faire:

newData[i].name = malloc(strlen(token) + 1); 
strcpy(newData[i].name, token); 

ou définir comme membre namechar name[64]; puis à nouveau strcpy(newData[i].name, token); sans malloc. Les 64 octets pour le nom peuvent être plus ou moins.