2010-05-11 7 views
0

J'ai un struct:Lire et écrire struct en C

typedef struct student 
{ 
     char fname[30]; 
     char sname[30]; 
     char tname[30]; 
     Faculty fac; 
     int course; 
     char group[10]; 
     int room; 
     int bad; 
} Student; 

Je l'ai lu à partir du fichier:

Database * dbOpen(char *fname) 
{ 
     FILE *fp = fopen(fname, "rb"); 
     List *lst, *temp; 
     Student *std; 
     Database *db = malloc(sizeof(*db)); 

     if (!fp) 
       return NULL; 

     FileNameS = fname; 

     std = malloc(sizeof(*std)); 
     if (!fread(std, sizeof(*std), 1, fp)) { 
       db->head = db->tail = NULL; 
       return db; 
     } 

     lst = malloc(sizeof(*lst)); 
     lst->s = std; 
     lst->prev = NULL; 
     db->head = lst; 
     while (!feof(fp)) { 
       fread(std, sizeof(*std), 1, fp); 
       temp = malloc(sizeof(*temp)); 
       temp->s = std; 
       temp->prev = lst; 
       lst->next = temp; 
       lst = temp; 
     } 
     lst->next = NULL; 
     db->tail = lst; 

     fclose(fp); 

     return db; 
} 

et moi avons un problème ... Au dernier enregistrement j'ai un tel pointeur de fichier: `fp 0x10311448 {_ptr = 0x00344b90 « ННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН НННННННННННННННННННННННННННННННННННННННННННН _ _iobuf *

` Et j'ai lu 2 fois le dernier enregistrement ...

Enregistrer le code du fichier:

void * dbClose(Database *db) 
{ 
     FILE *fp = fopen(FileNameS, "w+b"); 
     List *lst, *temp; 

     lst = db->head; 
     while(lst != NULL) { 
       fwrite(lst->s, sizeof(*(lst->s)), 1, fp); 
       temp = lst; 
       lst = lst->next; 
       free(temp); 
     } 
     free(db); 
     fclose(fp); 
} 
+0

Et ceci est l'une des nombreuses raisons pour lesquelles je suis venu à aimer les conteneurs STL. Il est facile d'oublier à quel point le code de la liste de débogage peut être amusant. –

+0

La description du problème que vous rencontrez n'est pas claire. Pourriez-vous élaborer? Aussi, je crois que le dernier morceau de code est dupliqué. –

Répondre

0

passe d'abord sans creuser trop profond encore, je dirais que vous avez écrit passer la fin de votre dossier. La sortie que vous affichez ressemble beaucoup à la sortie de la mémoire de débogage que vous verriez à la fin d'un tampon malloc. Votre base de données n'est peut-être pas alignée correctement? Vous cherchez un peu plus maintenant ...

2

quelques problèmes observés et Semblant que vous considériez:

(1) Que faire si votre lien de fichier en octets est pas exactement un multiple de sizeof(Student)? Ensuite ce code:

while (!feof(fp)) { 
    fread(std, sizeof(*std), 1, fp); 
    ... 

pouvait lire une struct partielle dans la mémoire pointée par std. Le contenu de std serait partiellement rempli et pourrait laisser une chaîne C non terminée en mémoire.

Vous devez vérifier la valeur de retour de fread().

(2) Ceci est un problème plus important. Vous réutilisez la mémoire allouée et pointée par std, bien que vous stockiez le pointeur dans chaque élément de votre liste liée.

Il semble que votre intention serait d'allouer une nouvelle mémoire pour chaque enregistrement Student. Dans ce cas, vous appelez malloc() dans le corps de la boucle qui lit plusieurs enregistrements du fichier.

Cette erreur dépend de la longueur du fichier, aussi - le fichier doit contenir plus d'un enregistrement. (3) Vous pouvez réorganiser votre code afin que le premier enregistrement soit également lu pendant une itération de boucle, pour supprimer le code dupliqué inutilement.

(4) Vous pouvez utiliser calloc() pour vous assurer que vous avez initialisé tous les enregistrements de Student.

Comme si:

Database * dbOpen(char *fname) 
{ 
    FILE *fp = fopen(fname, "rb"); 
    List *lst, *temp; 
    Student *std; 
    Database *db = NULL; 

    if (!fp) 
      return db; 

    FileNameS = fname; 

    db = malloc(sizeof(*db)); 
    db->head = NULL; 
    lst = NULL; 
    while (!feof(fp)) { 
      std = malloc(sizeof(*std)); 
      if (!fread(std, sizeof(*std), 1, fp)) 
      { 
       free(std); 
       fprintf(stderr, "Input file concludes in partial record.\n"); 
       break; 
      } 

      temp = malloc(sizeof(*temp)); 
      temp->s = std; 
      temp->prev = lst; 
      temp->next = NULL; 

      if (lst == NULL) 
       db->head = temp; 
      else 
       lst->next = temp; 
      lst = temp; 
    } 
    assert(lst->next == NULL); /* Now performed above by temp->next assignement. */ 
    db->tail = lst; 

    fclose(fp); 

    return db; 
} 

Je n'ai pas compiler et tester le code ci-dessus, mais il devrait être proche de travailler. Notez comment un cas spécial est ajouté pour initialiser db->head (première fois dans la boucle, avec lst égal NULL), sinon l'élément de liste précédent est lié à l'élément nouvellement ajouté (itérations ultérieures).Bien sûr, nous devrions également vérifier les valeurs de retour de malloc(), mais cela est omis pour plus de clarté ici.

+0

+1 pour repérer la réutilisation de 'std'! –

+0

Le point 1 montre un exemple canonique de la raison pour laquelle 'while (feof (...))' est généralement faux. Dans ce cas, il devrait simplement être 'while (fread (...) == 1)' – caf

0

Dans cette boucle:

while (!feof(fp)) { 
      fread(std, sizeof(*std), 1, fp); 
      temp = malloc(sizeof(*temp)); 
      temp->s = std; 
      temp->prev = lst; 
      lst->next = temp; 
      lst = temp; 
    } 

vous utilisez le résultat de la fread sans vérifier qu'il est revenu avec succès. Vous devez vérifier feof(fp) ou la valeur de retour de fread avant de supposer que les données ont été lues avec succès.

1

Ce se distingue pour moi:

while (!feof(fp)) { 
      fread(std, sizeof(*std), 1, fp); 
      temp = malloc(sizeof(*temp)); 
      temp->s = std; 
      temp->prev = lst; 
      lst->next = temp; 
      lst = temp; 
     } 

Vous ne devriez pas utiliser feof() comme condition de la boucle; l'indicateur de fin de fichier n'est pas défini avant que après vous essayez de lire au-delà de la fin du fichier, de sorte que votre boucle s'exécute un trop de fois. Restructurer votre boucle pour utiliser la valeur de retour de fread(), et vérifiez contre feof() que si fread() échoue:

while (fread(std, sizeof *std, 1, fp) == 1) 
{ 
    temp = malloc(sizeof *temp); 
    temp->s = std; 
    ... 
} 
if (feof(fp)) 
    // handle end of file 
else 
    // handle other read error