leggere struttura da file

Stefanokj

Utente Attivo
333
7
OS
Arch
Sto facendo un piccolo progetto dove devo gestire i dati di persone, ora devo creare una procedura che mi permetta di leggere da un file binario (il cui nome viene passato come parametro) una lista di persone. L’allocazione dinamica deve avvenire dentro la subroutine. Il file deve essere aperto e chiuso dentro la funzione. Il puntatore al vettore dinamico dovrà essere assegnato al relativo campo del parametro ‘dati’ così come il numero di elementi letti.

Ho due funzioni pronte per aprire e chiudere il file:

Codice:
FILE *openFile(char *nameFile, char *mode){   
   FILE *fp = fopen(nameFile, mode);    
   if(fp == NULL)       
     exit(-1);    
   return fp;
}

Codice:
FILE *closeFile(FILE * fp) {    
   if (fp != NULL)      
     fclose(fp);    
   return NULL;
}

Questa è l'implementazione della funzione loadData:

Codice:
void loadData(VD *data, char *namefile){   
     FILE* f = openFile(namefile,  "r");   
     char string[200]; //Non so quale dimensione dare alla stringa
     while(!feof(f)){    
   fgets(string,200,f);  
     }   
closeFile(f);
}

Dentro il file dat c'è per prima cosa il numero totale di strutture, poi ci sono i dati delle persone, ecco un esempio: https://pastebin.com/s4LxFNGE

Questo è VD:

Codice:
typedef struct{   
  RecordSubj *v;
  int nElements;
} VD;

Questa è l'implementazione di RecordSubj

Codice:
typedef struct { char name[SIZE_NAME + 1];   
  char surname[SIZE_SURNAME + 1];   
  int height;   
  float weight;   
  char eyeColor[DIM_COLOR];   
  char hairColor[DIM_COLOR];  
  hair hairLength;   
  _Bool beard;   
  _Bool scar;   
  char key[DIM_KEY];   
  char lives[SIZE_LIVES + 1];   
  GPSPosition position;   
  StateOf state;
} RecordSubj;

Mi potete aiutare?
PS Posso utilizzare solo librerie standard
 
Ultima modifica da un moderatore:

pabloski

Utente Èlite
2,868
916
Da quella struct vedo che ogni campo ha una dimensione fissa. Però nella traccia non è specificato. Questo è il primo dubbio che ho.

Altra questione riguarda la codifica dei record.

StateOf cos'è?? Stringa? Dimensione fissa?

GPSPosition?? Stringa? Struct?

Infine, non vedo nulla che possa servire per creare una lista/vettore di record. VD contiene un intero e un puntatore. A questo punto è necessario stabilire come s'intende gestire questo VD. Il primo campo potrebbe essere benissimo un RecordSubj **v, intendendolo come un array allocato dinamicamente di tipi RecordSubj. Altrimenti bisogna creare una lista, mettendo dei puntatori in RecordSubj che puntino agli elementi precedente e/o successivo della lista. Il che porrebbe un dilemma riguardo la codifica su file del record.
 

Stefanokj

Utente Attivo
333
7
OS
Arch
Da quella struct vedo che ogni campo ha una dimensione fissa. Però nella traccia non è specificato. Questo è il primo dubbio che ho.

Altra questione riguarda la codifica dei record.

StateOf cos'è?? Stringa? Dimensione fissa?

GPSPosition?? Stringa? Struct?

Infine, non vedo nulla che possa servire per creare una lista/vettore di record. VD contiene un intero e un puntatore. A questo punto è necessario stabilire come s'intende gestire questo VD. Il primo campo potrebbe essere benissimo un RecordSubj **v, intendendolo come un array allocato dinamicamente di tipi RecordSubj. Altrimenti bisogna creare una lista, mettendo dei puntatori in RecordSubj che puntino agli elementi precedente e/o successivo della lista. Il che porrebbe un dilemma riguardo la codifica su file del record.
SteteOf è un'enumerazione, può avere i seguenti valori: In arresto, libero, ricercato, altro.
anche hairLength: corti, medi, lunghi, altro.

GPSPosition è una struttura:
a)Latitudine (double)
b)Longitudine (double)

Per quanto riguarda l'allocazione non devo utilizzare liste ma obbligatoriamente array di strutture
 

pabloski

Utente Èlite
2,868
916
SteteOf è un'enumerazione, può avere i seguenti valori: In arresto, libero, ricercato, altro.
anche hairLength: corti, medi, lunghi, altro.

ottimo, quindi sono 8 bit e lunghezza fissa

GPSPosition è una struttura:
a)Latitudine (double)
b)Longitudine (double)

Per quanto riguarda l'allocazione non devo utilizzare liste ma obbligatoriamente array di strutture

anche questa è a lunghezza fissa ed è incorporata nell'altra

beh mi sa che ti conviene usare l'array di struct che avevo detto prima, così puoi scrivere il record su file com'è, senza aggiungere niente

altrimenti puoi usare il carattere ascii 30 che è il separatore di record
 

Stefanokj

Utente Attivo
333
7
OS
Arch
ottimo, quindi sono 8 bit e lunghezza fissa



anche questa è a lunghezza fissa ed è incorporata nell'altra

beh mi sa che ti conviene usare l'array di struct che avevo detto prima, così puoi scrivere il record su file com'è, senza aggiungere niente

altrimenti puoi usare il carattere ascii 30 che è il separatore di record
Non so se hai visto come sono scritti i dati all'interno del file: https://pastebin.com/s4LxFNGE
Cosa mi consigli per rimuovere i primi caratteri sino al : ?
Contando il : e lo spazio dopo di esso sono 26 caratteri da rimuovere per ogni riga
Post unito automaticamente:

Inoltre bisogna considerare che nella prima riga del file ho il numero di strutture all'interno di esso, quindi per la lettura del file devo leggere anche il numero di strutture e allocare.
Ovviamente poi devo saltare le righe vuote
 

Lorenzo Lanas

Utente Attivo
1,486
886
CPU
AMD Ryzen 5 5600X (Zen 3)
Dissipatore
Arctic Liquid Freezer II 360
Scheda Madre
MSI MAG B550 Tomahawk
RAM
Crucial Ballistix DDR4, 2x8GB, 3200 MHz, CL16
GPU
ASUS GeForce RTX 3060 Ti V2 DUAL MINI
Monitor
AOC 24G2U/BK 24" IPS, FHD 1920x1080 @ 144 Hz
PSU
Cooler Master Silent Pro Gold 600W
Case
Fractal Design Define 7 Solid Black&White
OS
Windows 10
Scusate se faccio una domanda banale ma frequento il forum da poco e quindi sono totalmente ignorante.

Ma questi post che vengono fatti (spesso) sono esercizi scolastici dati a scuola come compiti da svolgere agli studenti a casa? Perchè questo in particolare mi sembra esattamente questo, ossia un compito atto a stimolare lo studente ad usare una determinata funzione del linguaggio C.
 

pabloski

Utente Èlite
2,868
916
Non so se hai visto come sono scritti i dati all'interno del file: https://pastebin.com/s4LxFNGE
Cosa mi consigli per rimuovere i primi caratteri sino al : ?

ah ma quello è il formato del file? e dove lo vedono che è binario?

comunque lì vedo dei tab e la fscanf li supporta

p.s. ho notato che i tab sono stati rimossi e sostituiti da spazi...tanto meglio

in soldoni cominceresti col leggere il numero di record così

C:
char fasullo[64];
int numRecs;

fscanf(fp, "%s%s%s%d\n", fasullo, fasullo, fasullo, &numRecs);

quel fasullo ti serve perchè la fscanf legge token separati da spazi, cioè il primo blocco legge "Number", il secondo "of", il terzo "elements" e il quarto 10

ovviamente ti serve 10, gli altri tre li butti in una variabile dummy

la lettura delle righe avviene invece così

C:
char nomeCampo[64];
char sepCampo[64];
char valCampo[64];

fscanf(fp, "%s%s%s\n", nomeCampo, sepCampo, valCampo);

le righe vuote semplicemente le bypassa, quindi non te ne devi preoccupare

Inoltre bisogna considerare che nella prima riga del file ho il numero di strutture all'interno di esso, quindi per la lettura del file devo leggere anche il numero di strutture e allocare.
Ovviamente poi devo saltare le righe vuote

Post unito automaticamente:

Scusate se faccio una domanda banale ma frequento il forum da poco e quindi sono totalmente ignorante.

Ma questi post che vengono fatti (spesso) sono esercizi scolastici dati a scuola come compiti da svolgere agli studenti a casa? Perchè questo in particolare mi sembra esattamente questo, ossia un compito atto a stimolare lo studente ad usare una determinata funzione del linguaggio C.

a volte si e il forum vieta di dare la soluzione

ma non vieta di dare spiegazioni, dopo che l'op ha mostrato di aver almeno pensato ad una possibile soluzione

p.p.s. qualcuno potrebbe obiettare che un software moderno dovrebbe usare la fgets, che legge una riga alla volta, per poi fare il parsing di quanto letto...il problema è che il parsing ti complica la vita e nel tuo caso non lo vedo utile
 
Ultima modifica:

Lorenzo Lanas

Utente Attivo
1,486
886
CPU
AMD Ryzen 5 5600X (Zen 3)
Dissipatore
Arctic Liquid Freezer II 360
Scheda Madre
MSI MAG B550 Tomahawk
RAM
Crucial Ballistix DDR4, 2x8GB, 3200 MHz, CL16
GPU
ASUS GeForce RTX 3060 Ti V2 DUAL MINI
Monitor
AOC 24G2U/BK 24" IPS, FHD 1920x1080 @ 144 Hz
PSU
Cooler Master Silent Pro Gold 600W
Case
Fractal Design Define 7 Solid Black&White
OS
Windows 10
a volte si e il forum vieta di dare la soluzione

ma non vieta di dare spiegazioni, dopo che l'op ha mostrato di aver almeno pensato ad una possibile soluzione
Ottimo! Grazie per la spiegazione ?
 

Stefanokj

Utente Attivo
333
7
OS
Arch
in soldoni cominceresti col leggere il numero di record così

C:
char fasullo[64];
int numRecs;

fscanf(fp, "%s%s%s%d\n", fasullo, fasullo, fasullo, &numRecs);

quel fasullo ti serve perchè la fscanf legge token separati da spazi, cioè il primo blocco legge "Number", il secondo "of", il terzo "elements" e il quarto 10

ovviamente ti serve 10, gli altri tre li butti in una variabile dummy

la lettura delle righe avviene invece così

C:
char nomeCampo[64];
char sepCampo[64];
char valCampo[64];

fscanf(fp, "%s%s%s\n", nomeCampo, sepCampo, valCampo);

le righe vuote semplicemente le bypassa, quindi non te ne devi preoccupare
Il file che ho scritto è in txt, ed è una rappresentazione del file dat.
Grazie mille per l'aiuto che mi stai dando.
Secondo quanto mi hai consigliato ho fatto questo prototipo:


Che ne pensi?
I problemi che suppongo ci siano sono:
per i dati tipo altezza e peso, ho oltre il valore numerico anche "cm,kg" dovendo appunto estrarre solo il numero dovrei togliere queste due lettere.
Stessa cosa nelle coordinate che sono scritte così: S 44.764382° E 157.791228° qua essendoci lo spazio tra S/E e il numero stavo pensando di utilizzare il metodo che hai spiegato prima, (con un %s in più), per rimuovere i caratteri finali posso fare qualcosa del tipo %.8f?

PS Suppongo dovrei inizializzare il vettore utilizzando la procedura inizializzaVettoreDinamico che è definita così:
Codice:
void inizializzaVettoreDinamico(VD *vettore){
    vettore->v = NULL;
    vettore->nElementi = 0;
}
giusto?
 

pabloski

Utente Èlite
2,868
916
Il file che ho scritto è in txt, ed è una rappresentazione del file dat.

humm quindi il file dat ha un formato diverso? il che significa che fprintf non ti può essere d'aiuto


Che ne pensi?

per il formato che hai mostrato, va bene

per quello dat non saprei che dirti

per i dati tipo altezza e peso, ho oltre il valore numerico anche "cm,kg" dovendo appunto estrarre solo il numero dovrei togliere queste due lettere.

nel qual caso vanno letti come stringhe e poi trattati opportunamente

oppure li leggi come numeri e ci attacchi cm e kg successivamente

Stessa cosa nelle coordinate che sono scritte così: S 44.764382° E 157.791228° qua essendoci lo spazio tra S/E e il numero stavo pensando di utilizzare il metodo che hai spiegato prima, (con un %s in più), per rimuovere i caratteri finali posso fare qualcosa del tipo %.8f?

beh quelli sono fastidiosi, perchè c'è il simbolo ° alla fine, il che ovviamente significa che dà errore se cerchi di leggerli come numero

leggili come stringhe e poi li trasformi in double

PS Suppongo dovrei inizializzare il vettore utilizzando la procedura inizializzaVettoreDinamico che è definita così:
Codice:
void inizializzaVettoreDinamico(VD *vettore){
    vettore->v = NULL;
    vettore->nElementi = 0;
}
giusto?

visto che all'inizio del file c'è il numero di record contenuti, ti conviene fare un array di struct e allocare numRecs elementi dinamicamente

ti risparmi un sacco di casini
 

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!