PDA

Visualizza la versione completa : [C] Problema stampa di una struttura dati


goatboy
19-10-2013, 17:50
Salve a tutti :)
Ho questo codice che legge da file prima una stringa e poi un numero, fino al termine del file.
Per poter leggere anche stringhe di più parole ho usato la fgets. So che si dovrebbe fermare al carattere di new line (quindi alla fine della riga di testo).

while(!feof(fp)) {
fgets(studente->esamiSvolti[i], C, fp);
fscanf(fp, "%d", &studente->votiEsami[i]);
sommaVoti += studente->votiEsami[i];
i++;
}

N.B. La variabile C vale 100.

Quando vado a stampare, mi stampa una cosa così:


Esame: Esame1
Voto: Voto1
Esame:
Voto: 0
Esame: Esame2
Voto: Voto2
Esame:
Voto: 0


Mi da degli spazi vuoti e dei voti zero.. credo che il problema sia nella fgets, ma magari mi sbaglio. Il programma non da errori. Qualcuno sa aiutarmi?

YuYevon
19-10-2013, 17:55
Dallo snippet di codice che hai postato è difficile capire quale sia il problema. Posta il necessario per poterlo comprendere (come sono dichiarati "studente", "esamiSvolti", "C" etc?). Sarebbe utile anche un esempio di contenuto del file che stai provando a leggere.

goatboy
19-10-2013, 18:01
Questo è tutto il codice che riguarda l'apertura del file, la struttura dati e la stampa :)


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define R 30
#define C 100
#define L 20

typedef struct {
char nome[L];
char cognome[L];
char esamiSvolti[R][C];
int votiEsami[R];
int numeroEsami;
float mediaEsami;
} Studente;

/* Funzione principale */
int main(){
Studente *studente;
char nome[L], cognome[L], file[L];
int i;

// Alloco lo spazio in memoria
studente = (Studente*)malloc(sizeof(Studente));

// Acquisisco dati necessari per l'apertura del file..


// Chiamo la funzione di lettura da file a cui passo la struttura dati
leggiDaFile(file, studente);

// Stampa
printf("\nLo studente %s %s ha svolto i seguenti esami:\n", studente->nome, studente->cognome);
for(i=0; i<studente->numeroEsami; i++) { // ciclo da 0 a numeroEsami
printf("Esame: %sVoto: %d\n", studente->esamiSvolti[i], studente->votiEsami[i]);
}
// Stampa della media con 2 cifre decimali
printf("La sua media e' di: %.2f\n\n", studente->mediaEsami);


system("PAUSE");
return 0;
}


void leggiDaFile(char file[], Studente *studente) {
FILE *fp;
int voto, sommaVoti=0, i=0, j;
char esame[C];

fp=fopen(file, "r");
while(!feof(fp)) {
fgets(studente->esamiSvolti[i], C, fp);
fscanf(fp, "%d", &studente->votiEsami[i]);
sommaVoti += studente->votiEsami[i];
i++;
}
studente->numeroEsami = i;
studente->mediaEsami = (float)sommaVoti/i;

fclose(fp);
}

YuYevon
20-10-2013, 10:01
Non hai postato un esempio del file che stai tentando di leggere, tuttavia dal tuo codice deduco che sia qualcosa del genere:



esame1
voto1
esame2
voto2
...
esameN
votoN


dove un esame è una stringa e un voto un intero.

Se è così, puoi risolvere indicando esplicitamente alla fscanf() di leggere e scartare il carattere di newline subito dopo il numero:



fscanf(fp,"%d\n",&studente->votiEsami[i]);

goatboy
20-10-2013, 10:11
Puoi risolvere indicando esplicitamente alla fscanf() di leggere e scartare il carattere di newline subito dopo il numero:


fscanf(fp,"%d\n",&studente->votiEsami[i]);



Ti ringrazio molto :) .. gli errori banali sono quelli peggiori :jam:

YuYevon
20-10-2013, 10:45
gli errori banali sono quelli peggiori :jam:

Questo non è così banale come può sembrare. Le funzioni della famiglia *scanf() sono abbastanza "tricky", non a caso la man page relativa (http://linux.die.net/man/3/scanf) è piuttosto corposa. C'è chi suggerisce di evitare del tutto questa famiglia di funzioni per la lettura da file o da stdin e di ricorrere a work-around come leggere sempre il dato come stringa con la fgets() e poi convertirlo in intero con atoi(), ma per approfondimenti, nel caso ti interessi, ti rimando al web che se ne cade di articoli sull'argomento (si tratta comunque *quasi* esclusivamente di scuole di pensiero).

goatboy
20-10-2013, 12:41
Questo non è così banale come può sembrare. Le funzioni della famiglia *scanf() sono abbastanza "tricky", non a caso la man page relativa (http://linux.die.net/man/3/scanf) è piuttosto corposa. C'è chi suggerisce di evitare del tutto questa famiglia di funzioni per la lettura da file o da stdin e di ricorrere a work-around come leggere sempre il dato come stringa con la fgets() e poi convertirlo in intero con atoi(), ma per approfondimenti, nel caso ti interessi, ti rimando al web che se ne cade di articoli sull'argomento (si tratta comunque *quasi* esclusivamente di scuole di pensiero).

Sapevo da tempo che la scanf() è da evitare per problemi legati ad un possibile overflow, però se utilizzata bene, con il dovuto controllo sul valore di ritorno e l'utilizzo del parametro [width] (es. %20s) non vedo che altri problemi possa generare. Più che altro è una funzione "limitante", visto che vincola il tipo di input da considerare.
Ad ogni modo, per le stringhe ho sempre utilizzato la fgets(). Per i tipi numerici ho sempre utilizzato la scanf(), ma proverò a seguire il tuo consiglio. Grazie per la precisazione :)

YuYevon
20-10-2013, 13:23
proverò a seguire il tuo consiglio

In realtà ti illustravo una scuola di pensiero più che un metodo da me adottato che ti consiglio. Personalmente mi sono sempre trovato sufficientemente bene con le funzioni della famiglia *scanf(), con gli adeguati accorgimenti e la dovuta lettura della documentazione.

Loading