2010-10-07 5 views
2

Je dispose d'un fichier texte contenant les données sous la forme:Le moyen le plus simple de lire cette ligne de texte dans une structure?

Lee AUS 2 103 2 62 TRUE 
Check AUS 4 48 0 23 FALSE 
Mills AUS 8 236 0 69 FALSE 

je dois chaque ligne en un comme struct, mais je voudrais éviter d'utiliser des tableaux de longueur fixe (le problème avec fgets pour autant que je peut dire):

struct Data 
{ 
    char *sname; 
    char *country; 
    int *a; 
    int *b; 
    int *c; 
    int *d; 
    char *hsisno; 
}; 

Je suis très nouveau à C. Dois-je utiliser fscanf ou fgets?

+0

J'utilise habituellement strtok mais il peut y avoir un meilleur moyen – GWW

Répondre

4

fscanf signifie « scan de fichiers au format » et les données de l'utilisateur est sur le point de non formaté que vous pouvez obtenir.

Vous ne devez jamais utiliser des chaînes de format "%s" nues sur des données où vous ne disposez pas d'un contrôle absolu sur ce qui peut être lu.

La meilleure solution consiste à utiliser fgets pour lire une ligne car cela vous permet d'empêcher le débordement de la mémoire tampon.

Ensuite, une fois que vous connaissez la taille de votre ligne, c'est la taille maximale de chaque chaîne dont vous aurez besoin. Utilisez sscanf à votre guise pour obtenir les champs réels.

Une dernière chose. Il est probablement un peu inutile d'avoir int* types pour les entiers, puisque vous savez qu'ils ont déjà une taille maximale spécifique. J'utilise la variante non-pointeur, quelque chose comme:

struct Data { 
    char *sname; char *country; 
    int a; int b; int c; int d; 
    char *hsisno; 
}; 

A titre d'exemple, voici un code sûr:

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

// Here's all the stuff for a linked list of your nodes. 

typedef struct sData { 
    char *sname; char *country; char *hsisno; 
    int a; int b; int c; int d; 
    struct sData *next; 
} Data; 
Data *first = NULL; Data *last = NULL; 

#define MAXSZ 100 
int main (void) { 
    char line[MAXSZ], sname[MAXSZ], country[MAXSZ], hsisno[MAXSZ]; 
    int a, b, c, d; 
    FILE *fIn; 
    Data *node; 

    // Open the input file. 

    fIn = fopen ("file.in", "r"); 
    if (fIn == NULL) { 
     printf ("Cannot open file\n"); 
     return 1; 
    } 

    // Process every line. 

    while (fgets (line, sizeof(line), fIn) != NULL) { 
     // Check line for various problems (too short, too long). 

     if (line[0] == '\0') { 
      printf ("Line too short\n"); 
      return 1; 
     } 

     if (line[strlen (line)-1] != '\n') { 
      printf ("Line starting with '%s' is too long\n", line); 
      return 1; 
     } 

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

     // Scan the individual fields. 

     if (sscanf (line, "%s %s %d %d %d %d %s", 
      sname, country, &a, &b, &c, &d, hsisno) != 7) 
     { 
      printf ("Line '%s' didn't scan properly\n", line); 
      return 1; 
     } 

     // Allocate a new node to hold data. 

     node = malloc (sizeof (Data)); 
     if (node == NULL) { 
      printf ("Ran out of memory\n"); 
      return 1; 
     } 

     node->sname = strdup (sname); 
     node->country = strdup (country); 
     node->a = a; 
     node->b = b; 
     node->c = c; 
     node->d = d; 
     node->hsisno = strdup (hsisno); 
     node->next = NULL; 
     if (first != NULL) { 
      last->next = node; 
      last = node; 
     } else { 
      first = node; 
      last = node; 
     } 
    } 

    fclose (fIn); 

    // Output the list for debugging. 

    node = first; 
    while (node != NULL) { 
     printf ("'%s' '%s' %d %d %d %d '%s'\n", 
      node->sname, node->country, node->a, node->b, 
      node->c, node->d, node->hsisno); 
     node = node->next; 
    } 

    return 0; 
} 

qui se lit dans votre fichier et le stocke dans un liste liée. Il sort:

'Lee' 'AUS' 2 103 2 62 'TRUE' 
'Check' 'AUS' 4 48 0 23 'FALSE' 
'Mills' 'AUS' 8 236 0 69 'FALSE' 

à la fin, comme prévu.


Je l'ai fait toute une série de réponses sur les pièges de l'utilisation *scanf fonctions sur des données non contrôlées (entrer user:14860 fgets dans la zone de recherche ci-dessus), dont certains (here, here et here, par exemple) inclure une fonction préférée éternelle du mien, getLine, pour une entrée plus sûre de l'utilisateur.

+0

Merci. Mais les fgets ne vous demandent-ils pas de connaître la taille de votre ligne, car elle a besoin du paramètre de taille de la mémoire tampon? –

+0

Habituellement, les gens utilisent une taille plus grande que ce à quoi ils s'attendaient dans le fichier. – GWW

+0

D'accord, c'est ce que j'allais faire, mais je me suis dit que c'est une mauvaise odeur de code. –

Questions connexes