PDA

View Full Version : [C] funzione che legge da .txt e trascive in una struttura concatenata


wickedwonderland
13-02-2016, 09:01
Salve, sto svolgendo un esercizio dove devo fare varie operazioni sulla programmazione di un cinema,a partire dai biglietti.

la lista dei biglietti è scritta in un file .txt secondo il seguente ordine (esempio) :
codice data ora sala tipologia
456123 03-02-2015 21:00 B 3D

devo utilizzare quindi una struct concatenata di questo tipo :

struct biglietto {
int codice;
int dd;
int mm;
int yy;
int h;
int m;
char sala;
int tipologiaa;
struct biblietto *next;
};

come posso implementare una funzione che, letti i dati dei biglietti da un file .txt, li scriva nella struttura concatenata ?
grazie

gianmpu
13-02-2016, 10:34
Benvenuto nel forum di hwupgrade.
Come in molti ti diranno, è vietato da regolamento chiedere la soluzione di esercizi.
E' permesso invece correggere eventuali errori nel codice che tu hai scritto finora dopo che lo avrai postato. ;)

wickedwonderland
13-02-2016, 17:06
Benvenuto nel forum di hwupgrade.
Come in molti ti diranno, è vietato da regolamento chiedere la soluzione di esercizi.
E' permesso invece correggere eventuali errori nel codice che tu hai scritto finora dopo che lo avrai postahttp://www.hwupgrade.it/forum/newreply.php?do=newreply&p=43373659to. ;)

chiedevo la risoluzione da zero proprio perchè non so lavorare con le struct concatenate, quindi il mio codice sarebbe stato inesistente. non è un esercizio assegnato e non ne traggo vantaggio dalla corretta risoluzione, era solo a scopo di apprendimento. ma se questo è il regolamento, mi ci attengo ;) .

ho provato a trascrivere i dati dal file ad un array di strutture, un po più macchinoso, ma che dovrebbe fare il suo lavoro, in questo modo :


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//definisco la struttura per salvare i biglietti

struct biglietto{
int codice;
int gg;
int mm;
int aa;
int h;
int m;
char sala;
int dimensione;
};


//funzione che calcola il numero di biglietti totali

int ContaLinee(FILE *f) {

char ch;
int linee = 0;
while(!feof(f)){
if ((ch = getc(f)) == '\n')
linee++;
}
return linee;
}


//funzione che legge i biglietti dal file e li copia nella struct

void LeggiBiglietto(FILE *f, struct biglietto *b, int NumB) {
int i;
for (i=0; i < NumB; i++){
fscanf(f,"%d %d-%d-%d %d:%d %c %d", &b[i].codice, &b[i].gg, &b[i].mm, &b[i].aa, &b[i].h, &b[i].m, &b[i].sala, &b[i].dimensione);
}
}


//main

int main(int argc, char **argv) {

FILE *f;
f = fopen(argv[1],"r");

int NumB;
NumB = ContaLinee(f);
printf("il numero di biglietti emessi è : %d \n", NumB);

struct biglietto *b[NumB];

LeggiBiglietto(f, b[NumB], NumB);

int i;
for (i = 0; i < NumB; i++ ) {
printf("il codice è : %d \n", b[i].codice);
printf("la data è : %d-%d-%d \n", b[i].gg, b[i].mm, b[i].aa);
printf("l'orario di inizio è : %d:%d \n", b[i].h, b[i].m);
printf("la sala è : %c \n", b[i].sala);
printf("il film è in %dD \n", b[i].dimensione);
}
}

sfortunatamente non compila dandomi questo errore di cui non riesco a venirne a capo:

esercizio.c:60:38: error: request for member ‘codice’ in something not a structure or union
printf("il codice è : %d \n", b[i].codice);
^
esercizio.c:61:42: error: request for member ‘gg’ in something not a structure or union
printf("la data è : %d-%d-%d \n", b[i].gg, b[i].mm, b[i].aa);
^
esercizio.c:61:51: error: request for member ‘mm’ in something not a structure or union
printf("la data è : %d-%d-%d \n", b[i].gg, b[i].mm, b[i].aa);
^
esercizio.c:61:60: error: request for member ‘aa’ in something not a structure or union
printf("la data è : %d-%d-%d \n", b[i].gg, b[i].mm, b[i].aa);
^
esercizio.c:62:50: error: request for member ‘h’ in something not a structure or union
printf("l'orario di inizio è : %d:%d \n", b[i].h, b[i].m);
^
esercizio.c:62:58: error: request for member ‘m’ in something not a structure or union
printf("l'orario di inizio è : %d:%d \n", b[i].h, b[i].m);
^
esercizio.c:63:36: error: request for member ‘sala’ in something not a structure or union
printf("la sala è : %c \n", b[i].sala);
^
esercizio.c:64:38: error: request for member ‘dimensione’ in something not a structure or union
printf("il film è in %dD \n", b[i].dimensione);

gianmpu
13-02-2016, 20:27
Questa linea
struct biglietto *b[NumB]
dichiara un array di puntatori. Dal momento che ogni elemento dell'array è un puntatore ad una struct nel codice non puoi avere accesso direttamente al contenuto della struct con espressioni del tipo b[indice numerico].
Comunque, data la richiesta, c'è proprio un errore di base su cosa sia una lista concatenata.
Una lista concatenata è qualcosa composto da singoli elementi che di solito si indicano nodi, fatti in questo modo
struct nodo {
dati da salvare
puntatore al nodo successivo
};
Dove "dati da salvare" indica i dati di cui si deve tenere traccia nel singolo elemento della lista(nel tuo caso quelli di un singolo biglietto, per capirci) e puntatore al nodo successivo è un puntatore all'elemento successivo della lista.
Con le liste concatenate, di solito basta tenere traccia del puntatore al primo elemento della lista perchè è possibile raggiungere un elemento seguente "navigando" da un elemento all'altro grazie al puntatore al nodo successivo.
Gli algoritmi di inserimento di un elemento sono standard e si trovano facilmente in qualunque dispensa disponibile in rete che tratti i puntatori in C. ;)

wickedwonderland
14-02-2016, 15:20
Questa linea
struct biglietto *b[NumB]
dichiara un array di puntatori. Dal momento che ogni elemento dell'array è un puntatore ad una struct nel codice non puoi avere accesso direttamente al contenuto della struct con espressioni del tipo b[indice numerico].
Comunque, data la richiesta, c'è proprio un errore di base su cosa sia una lista concatenata.
Una lista concatenata è qualcosa composto da singoli elementi che di solito si indicano nodi, fatti in questo modo
struct nodo {
dati da salvare
puntatore al nodo successivo
};
Dove "dati da salvare" indica i dati di cui si deve tenere traccia nel singolo elemento della lista(nel tuo caso quelli di un singolo biglietto, per capirci) e puntatore al nodo successivo è un puntatore all'elemento successivo della lista.
Con le liste concatenate, di solito basta tenere traccia del puntatore al primo elemento della lista perchè è possibile raggiungere un elemento seguente "navigando" da un elemento all'altro grazie al puntatore al nodo successivo.
Gli algoritmi di inserimento di un elemento sono standard e si trovano facilmente in qualunque dispensa disponibile in rete che tratti i puntatori in C. ;)

capisco, quindi in questo caso non ho alternative se non usare una lista concatenata.
scusami se ti disturbo nuovamente, ho googlato un po' alla ricerca di una guida valida che spiegasse l'inserimento e la lettura dei dati nelle liste dinamiche ma non ne ho trovata neanche una , quelle qui sul forum sono ad un livello molto più avanzato, e la maggior parte di quelle nelle dispense universitarie si limitano alla sola definizione di questo tipo di strutture, sapresti dirmi dove posso trovarne una valida ?

gianmpu
15-02-2016, 12:42
In realtà non è una questione di alternative, quanto piuttosto di traccia dell'esercizio.
Esiste infatti sempre la possibilità di utilizzare al posto della lista concatenata un array opportunamente dimensionato, ma nel tuo caso, se non ho capito male, visto che si tratta di un esercizio viene espressamente chiesto l'uso della lista. E' corretto?
Proporre una dispensa adatta al tuo livello è difficile perchè non so qual è il tuo livello attuale di conoscenza.
Comunque, cercando su google, ho trovato questa dispensa
http://www.science.unitn.it/~brunato/labpro1/lista.html
Rispetto ad altre guide, ha il vantaggio della notazione grafica.
Quando si affrontano le liste concatenate per la prima volta, infatti, aiutarsi con una notazione grafica che spieghi visivamente le operazioni che vengono effettuate può aiutare a rendere l'argomento meno ostico. ;)

wickedwonderland
15-02-2016, 19:52
In realtà non è una questione di alternative, quanto piuttosto di traccia dell'esercizio.
Esiste infatti sempre la possibilità di utilizzare al posto della lista concatenata un array opportunamente dimensionato, ma nel tuo caso, se non ho capito male, visto che si tratta di un esercizio viene espressamente chiesto l'uso della lista. E' corretto?
Proporre una dispensa adatta al tuo livello è difficile perchè non so qual è il tuo livello attuale di conoscenza.
Comunque, cercando su google, ho trovato questa dispensa
http://www.science.unitn.it/~brunato/labpro1/lista.html
Rispetto ad altre guide, ha il vantaggio della notazione grafica.
Quando si affrontano le liste concatenate per la prima volta, infatti, aiutarsi con una notazione grafica che spieghi visivamente le operazioni che vengono effettuate può aiutare a rendere l'argomento meno ostico. ;)

Nella traccia dell'esercizio l'utilizzo di una lista concatenata é consigliato come metodo più efficiente , io sono andato sulla fiducia , ho sbagliato ?
Il mio livello nella programmazione C temo sia il più basso possibile :doh: .
Ti ringrazio per la guida linkata , la rappresentazione grafica aiuta molto :D

gianmpu
15-02-2016, 20:28
Si, una lista concatenata è più efficiente.
Come detto, infatti, si potrebbe usare anche un array al posto della lista.
L'array però di solito deve avere una dimensione fissata a priori tale che possa contenere al suo interno i dati del numero massimo di biglietti quindi spesso comporta uno spreco di memoria perchè non sempre tale numero di biglietti viene venduto. La lista, invece, alloca la memoria in cui salvare i dati solo quando ce n'è veramente bisogno quindi non comporta sprechi.

GTKM
16-02-2016, 10:19
Le liste presentano, inoltre, ulteriori vantaggi rispetto agli array (se sono doppiamente concatenate, poi... :D ).
Ad esempio, l'inserimento ordinato è molto meno dispendioso (in termini di operazioni da eseguire). Immagina di voler inserire un elemento a metà lista. Se usassi un array (fermo restando il problema delle dimensioni fissate a compile-time) dovresti prima spostare tutti gli elementi che dovranno seguire quello da inserire, e poi potresti inserirlo.
Usando le liste, invece, si tratta solo di modificare i riferimenti di, al massimo, 4 puntatori, senza che siano necessarie ulteriori operazioni in memoria (infatti, i singoli elementi di una lista non sono memorizzati necessariamente in locazioni contigue).

Ovviamente, hanno anche degli svantaggi. Ad esempio, se vuoi accedere all'elemento "n" di un array, è sufficiente scrivere nome_array[n]. Nel caso di una lista, invece, devi necessariamente partire dal puntatore alla testa e scorrerla. Inoltre, se per errore perdi il puntatore alla testa della lista, non c'è modo di recuperarla (infatti, è buona norma creare un puntatore "temporaneo" per scorrere la lista, senza toccare "head").

In definitiva, la scelta tra array e liste, al di là di preferenze personali, va fatto, in linea di massima, ragionando così:

Se il programma dovrà accedere molte volte agli elementi, ma in sola lettura (quindi, quando il numero di letture è molto superiore al numero di inserimenti e rimozioni), gli array sono preferibili (fermo restando, ripeto, il limite dato dalla dimensione prefissata).

Viceversa, meglio le liste.

wickedwonderland
17-02-2016, 10:08
Si, una lista concatenata è più efficiente.
Come detto, infatti, si potrebbe usare anche un array al posto della lista.
L'array però di solito deve avere una dimensione fissata a priori tale che possa contenere al suo interno i dati del numero massimo di biglietti quindi spesso comporta uno spreco di memoria perchè non sempre tale numero di biglietti viene venduto. La lista, invece, alloca la memoria in cui salvare i dati solo quando ce n'è veramente bisogno quindi non comporta sprechi.

Le liste presentano, inoltre, ulteriori vantaggi rispetto agli array (se sono doppiamente concatenate, poi... :D ).
Ad esempio, l'inserimento ordinato è molto meno dispendioso (in termini di operazioni da eseguire). Immagina di voler inserire un elemento a metà lista. Se usassi un array (fermo restando il problema delle dimensioni fissate a compile-time) dovresti prima spostare tutti gli elementi che dovranno seguire quello da inserire, e poi potresti inserirlo.
Usando le liste, invece, si tratta solo di modificare i riferimenti di, al massimo, 4 puntatori, senza che siano necessarie ulteriori operazioni in memoria (infatti, i singoli elementi di una lista non sono memorizzati necessariamente in locazioni contigue).

Ovviamente, hanno anche degli svantaggi. Ad esempio, se vuoi accedere all'elemento "n" di un array, è sufficiente scrivere nome_array[n]. Nel caso di una lista, invece, devi necessariamente partire dal puntatore alla testa e scorrerla. Inoltre, se per errore perdi il puntatore alla testa della lista, non c'è modo di recuperarla (infatti, è buona norma creare un puntatore "temporaneo" per scorrere la lista, senza toccare "head").

In definitiva, la scelta tra array e liste, al di là di preferenze personali, va fatto, in linea di massima, ragionando così:

Se il programma dovrà accedere molte volte agli elementi, ma in sola lettura (quindi, quando il numero di letture è molto superiore al numero di inserimenti e rimozioni), gli array sono preferibili (fermo restando, ripeto, il limite dato dalla dimensione prefissata).

Viceversa, meglio le liste.

Grazie ed entrambi, ieri ho scribacchiato basandomi sulla pagina linkata da Gianmpu e su un'altra trovata online, questo è il risultato :


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LINEA_MAX 30


struct cinema {
int codice;
int dd;
int mm;
int yy;
int h;
int m;
char sala;
int tipo;
struct cinema *next;
};


//funzione per eliminare la memoria allocata

void libera_memoria(struct cinema *b) {

struct cinema *temp;
while(b != NULL) {
temp = b;
b = b->next;
free(temp);
}
}

//funzione che legge i dati e li mette nella struttura

struct cinema *leggi_biglietto(const char *nomefile) {

FILE *f;
f = fopen(nomefile,"r");
if (f == NULL) {
printf("errore nell'apertura del file");
return NULL;
}

struct cinema *biglietto = NULL;
struct cinema *b;
char linea[LINEA_MAX + 1];
int n;

while(fgets(linea,LINEA_MAX + 2,f) != NULL) {
b = (struct cinema*) malloc(sizeof(struct cinema));
b->next = biglietto;
biglietto = b;
n = sscanf(linea,"%d %d-%d-%d %d:%d %c %d", &b->codice, &b->dd, &b->mm, &b->yy, &b->h, &b->m, &b->sala, &b->tipo);
if (n == 0) {
biglietto = biglietto->next;
free(b);
} else if (0 < n && n < 8) {
printf("numero di campi non validi");
return NULL;
}
}
fclose(f);
if (biglietto == NULL) {
printf("errore nella lettura dei dati");
return NULL;
}
return biglietto;
}




int main(int argc,char **argv) {

//lettura dati

struct cinema *biglietto;
biglietto = leggi_biglietto(argv[1]);


//fine

libera_memoria(biglietto);
}

funziona :eek: :Prrr: :)
potrei migliorarlo in qualche modo ?