PDA

Visualizza la versione completa : lettura di un file binario con fread C


myricio
18-01-2014, 18:34
buondì a tutti!

sono 3 giorni che cerco di risolvere un esercizio lasciato dal mio prof e dato che ho l'esame di fondamenti tra una settimana è meglio che abbia chiaro quest'ultimo passaggio :P

l'esercizio consiste nel creare una funzione capace di memorizzare da un file binario i valori di 3 campi "nome" "cognome" "telefono".

ora, gli errori possono essere due:
o sto allocando male la memoria (non mi pare),
o dopo 130412 prove continuo a fare degli errori nella gestione di fread (molto probabile)

io per darvi un'idea chiara posto sia tutto il sorgente che anche il file .bin
nel mentre vado a studiare analisi :P
grazie in anticipo!



#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>


/* definisco la struttura */


struct contatto {
char nome[255];
char cognome[255];
char telefono[255];
};
struct contatto *link;


/* corpo della prima1 funzione */


void contatto_read_bin (struct contatto *pc, FILE *f) {
link = malloc(sizeof(struct contatto));
fread(pc->nome, sizeof(char), 255, f);
fread(pc->cognome, sizeof(char), 255, f);
fread(pc->telefono,sizeof(char), 255, f);


}
/* corpo della seconda funzione


void contatto_print (struct contatto *pc, FILE *f) {


}
*/


main(){
FILE *frp;
FILE *fwp;
frp=fopen("contatto1.bin", "rb");
fwp=fopen("contatto.txt", "rt");
if (frp==NULL || fwp==NULL){
printf("errore nell'apertura di un file");
system("pause");
exit(1);
}
contatto_read_bin (link, frp);
printf("\n i valori letti dal file sono: \n nome: %s \ncognome: %s \n numero di telefono: %s.", link->nome, link->cognome, link->telefono);
/*
contatto_print (pc, fwp); */
}




siccome html.it non prevede l'upload di file .bin vi lascio il link al file uppato su mega:
https://mega.co.nz/#!8g4FBaBA!LJflRCkXF97pY31q6Bfk3m9M2etvVe4k6bG7CuA cTTA

oregon
18-01-2014, 18:54
Beh, la fread c'entra poco ... comunque, la chiamata dovrebbe essere



contatto_read_bin (&link, frp);


e la funzione



void contatto_read_bin (struct contatto **pc, FILE *f) {
*pc = (struct contatto *)malloc(sizeof(struct contatto));
fread((*pc)->nome, sizeof(struct contatto), 1, f);
}

myricio
18-01-2014, 19:11
beh.. che dire, funziona.. ma sono perplesso perchè in tutti gli altri esercizi gestivo bene le struct come nel mio codice..
mi spieghi qual'è l'utilità di utilizzare un doppio puntatore nella funzione e gestire le struct sempre col doppio puntatore?
se non mi sbaglio scrivere (*pc)-> è come scrivere (*(*pc)) non ne trovo un senso!
e già che ci siamo, il cast nella malloc.. è un dubbio che mi tiro dietro da un pò, a me ha sempre funzionato a meraviglia senza, com'è possibile? anche perchè la malloc ritorna void.

oregon
18-01-2014, 19:18
Il cast della malloc è solo una buona abitudine che mi deriva dal compilatore C++ (per cui è obbligatorio, al contrario del C).

Per il puntatore, nota che nel tuo codice avevi utilizzato direttamente link per la malloc (dato che era visibile) ma dovevi utilizzare l'argomento passato. E se vuoi modificare un argomento questo deve essere passato per puntatore. Quindi, un puntatore da modificare deve essere un doppio puntatore.

myricio
18-01-2014, 19:19
non ho capito quello che hai scritto, scusami.. in che senso argomento passato?
comunque cambiando la fread il programma funziona..


#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>


/* definisco la struttura */


struct contatto {
char nome[255];
char cognome[255];
char telefono[255];
};
struct contatto *link;


/* corpo della prima1 funzione */


void contatto_read_bin (struct contatto *pc, FILE *f) {
fread(pc->nome, sizeof(struct contatto), 1, f);
fread(pc->cognome, sizeof(struct contatto), 1, f);
fread(pc->telefono,sizeof(struct contatto), 1, f);


}
/* corpo della seconda funzione


void contatto_print (struct contatto *pc, FILE *f) {


}
*/


main(){
FILE *frp;
FILE *fwp;
frp=fopen("contatto1.bin", "rb");
fwp=fopen("contatto.txt", "rt");
link = malloc(sizeof(struct contatto));
if (frp==NULL || fwp==NULL){
printf("errore nell'apertura di un file");
system("pause");
exit(1);
}
contatto_read_bin (link, frp);
printf("i valori letti dal file sono: \nnome: %s \ncognome: %s \nnumero di telefono: %s.\n", link->nome, link->cognome, link->telefono);
system("pause");
/*
contatto_print (pc, fwp); */
}

oregon
18-01-2014, 19:22
e infatti... alla fine ho corretto

Beh ... se cambi le carte in tavola, cambia il codice.

Adesso non fai la malloc all'interno della funzione ma nel main prima di chiamarla.
A questo punto non c'è bisogno di doppio puntatore perché non lo modifichi all'interno della funzione.

Ma la fread resta usata male dato che deve essere solamente



void contatto_read_bin (struct contatto *pc, FILE *f) {
fread(pc, sizeof(struct contatto), 1, f);
}

myricio
18-01-2014, 19:30
okay, fooorse comincio a seguirti :-)
detto in maniera molto brutale nel codice che mi hai scritto tu stiamo dicendo:
ho un puntatore 1,
poi faccio una malloc dentro la funzione in un puntatore 2,
ma passo all'interno della funzione il mio puntatore 1 e faccio in modo che punti al puntatore 2 che punta alla memoria che sennò andrebbe persa e quindi ritrovo un doppio puntatore(allo stesso elemento)?

per quanto riguarda fread questa provvede ad inserire nei vari vettori i 3 campi man mano che li va trovando in automatico? così è più comodo. Purtroppo è una funzione che odio e non andiamo molto d'accordo

oregon
18-01-2014, 19:34
Mah ... non so se ho seguito (e capito) il tuo ragionamento sui puntatori e sui puntatori a puntatori ...

La fread legge un certo numero di byte dal file e li inserisce in sequenza in memoria. Dato che nella struttura sono in sequenza puoi leggerli tutti insieme. E' una delle funzioni più semplici che ci siano.

myricio
18-01-2014, 19:38
chiaro.
posso chiederti di provare a ri-argomentarmi in maniera più semplice la parte sui doppi puntatori. Vorrei capirla bene :(

myricio
19-01-2014, 16:49
e un'altra cosa Oregon, se vuoi, puoi spiegarmi il modo canonicamente corretto di usare fread ed fwrite? nel senso che se ora io voglio scrivere su un altro file usando fwrite cosa devo fare? e se avessi inoltre avuto più file di tipo contatto (tipo avere 3 contatti da leggere quindi fare la malloc scritta sopra ma moltiplicata per 3) per leggerli con fread in sequenza che parametro dovevo cambiare dato che nel tuo esempio specifico soloil puntatore a contatto? grazie in anticipo

Loading