2013-02-22 7 views
2

J'ai un devoir et j'ai eu un peu de difficulté. Le code suivant est censé prendre l'entrée d'un fichier, le lire dans une structure que j'ai définie et le faire sans aucune limite au nombre de lignes d'entrée. Cependant, il segfaults à la ligne 24 :Utilisation de fscanf pour entrer des données dans un tableau de pointeurs struct struct?

1 #include <stdio.h> 
2 #include <stdlib.h> 
3 #include <string.h> 
4 
5 typedef struct __student { 
6   int ID; 
7   char fname[33]; 
8   char lname[33]; 
9   float grade; 
10 } student; 
11 
12 void partA(FILE *fp) { 
13 
14   int i, r; 
15   i = r = 0; 
16   int N = 1000; 
17   student **S; 
18 
19   S = (student **)malloc(sizeof(student *) * N); 
20 
21 
22   while(!feof(fp)){ 
23     fscanf(fp, "%d %[^,], %s %f", &S[i]->ID, S[i]->lname, S[i]->fname, &S[i]->grade); // segfault occurs on this line 
24     printf("%d %s %s %f\n", S[i]->ID, S[i]->fname, S[i]->lname, S[i]->grade); 
25     i++; 
26     printf("Something's happening, at least"); 
27     if(i == N){ 
28       N *= 2; 
29       S = (student **)realloc(S, sizeof(student) * N); 
30       if(S == NULL) { 
31         printf("Memory reallocation failed; Fatal error."); 
32         break; 
33       } 
34     } 
35   } 
36 } 

Je l'ai testé le code avant, mais à ce moment-là que j'utilisais les tableaux statiques et je voulais passer à une taille dynamique. Cependant, même gdb avec offre très peu d'aide en plus du numéro de ligne. Ai-je besoin de malloc individuellement chaque étudiant struct, ou ai-je manqué quelque chose de complètement différent ici?

EDIT: Il semble que le code fonctionne quand j'allouer de la mémoire à chaque élève dans la boucle while par:

S[i] = (student *)malloc(sizeof(student)); 

donc qui semble avoir résolu le problème. Je vais faire quelques tests pour être sûr.

+0

Cela ressemble à un tableau impair \ liste de liens \ 2D. Lequel veux-tu? – andre

+0

Pourriez-vous expliquer le format des lignes d'entrée? '"% d% [^,],% s% f "' Pourquoi faites-vous cela avec '',''? –

+1

andre, c'était un oubli, je m'excuse. J'ai essayé une approche LL plus tôt, mais j'ai trouvé que ce n'était pas ce dont j'avais besoin. @ AdriánLópez Les données d'entrée sont au format , . J'utilise simplement un scanset pour me débarrasser de la virgule. Mes excuses pour ne pas mentionner cela! – user991710

Répondre

0

Sur la ligne 19, vous allouez suffisamment d'espace pour N pointeurs d'étudiant, mais n'allouez pas d'espace pour que l'étudiant se structure lui-même. Vous devez faire quelque chose comme:

for(int i = 0; i < N; i++) { 
    S[i] = malloc(sizeof(struct __student)); 
} 
+0

Oh oups semble que vous avez répondu à votre propre question avec l'édition. –

+0

Je l'ai fait, mais je vais accepter la réponse de toute façon puisque c'est la bonne. Je vous remercie. – user991710

1

En plus de votre problème de malloc, vous avez des problèmes majeurs avec les deux lignes

while(!feof(fp)){ 
    fscanf(fp, "%d %[^,], %s %f", &S[i]->ID, S[i]->lname, S[i]->fname, &S[i]->grade); // segfault occurs on this line 

Un problème est que vos lname et fname champs sont taille fixe 33 tableaux char , ce qui signifie que si votre entrée a plus de 32 caractères à ce moment-là, vous allez quitter la fin du tableau et corrompre les choses. Un autre problème est que vous ne vérifiez pas la valeur de retour de fscanf pour voir si quelque chose s'est mal passé (comme un EOF), vous incitant à essayer d'imprimer un enregistrement de la poubelle lorsque vous arrivez à la fin du fichier. Ce que vous voulez à la place est quelque chose comme:

while (fscanf(fp, "%d %32[^,],%32s%f", &S[i]->ID, S[i]->lname, S[i]->fname, &S[i]->grade) == 4) { 

pour votre contrôle de boucle.

modifier

Le problème avec while(!feof(fp)) (et pourquoi il est presque toujours une erreur) est que feof(fp) ne retourne vrai après que vous avez essayé de lire après la fin du fichier. Après avoir lu la dernière ligne, feof(fp) renvoie toujours false, de sorte que vous revenez dans la boucle et essayez de lire une autre ligne. Cette lecture échoue, mais puisque vous ne vérifiez pas la valeur de retour de fscanf, vous ne le réalisez pas et obtenez à la place une valeur supplémentaire dans votre tableau.

+0

Merci pour votre réponse. La raison pour laquelle je ne vérifie pas la taille d'entrée est parce que, comme je l'ai dit, il s'agit d'une affectation et la taille d'entrée est garantie pour être cohérente. J'aurais vérifié pour ça autrement, bien sûr. Merci d'avoir mentionné la valeur de retour, je devrais en effet prendre l'habitude de l'utiliser dans la mesure du possible pour détecter les erreurs. Une chose: quelle serait la différence entre while (! Feof (fp)) et while (fscanf (...) == 4), ici? Puisque je lis d'une entrée cohérente, ne pas être en mesure de faire correspondre les éléments équivaudrait essentiellement à être EOF, non? Je vous remercie. – user991710