Un esercizio non difficile in se ma piuttosto articolato. Si vuole prenotare un posto su un treno caricando un file con precedenti prenotazioni, effettuare la scelta di un posto e quindi riscrivere il file aggiornato. Vediamo come
Vogliamo costruire un treno in cui inseriamo più che posti le prenotazioni in ordine sparso. Ad ogni esecuzione del programma si potrà prenotare un solo posto e nel treno ci saranno solo 100 posti divisi tra 20 di prima classe e 80 di seconda. Non è necessario che i posti di prima e seconda classe siamo raggruppati, ma possono essere memorizzati in ordine sparso in fase di prenotazione. Al termine della prenotazione il software svolgerà un salvataggio dei dati nel file di testo: prenota_posti_treno.dat. Questo file, ogni volta viene lanciato, verrà letto con i precedenti dati esistenti e caricati su opportuna struttura dati. Creiamo le funzioni necessarie alla visualizzazione dei posti ed alcuni dati statistici di contorno.
La struttura che gestisce la prenotazione deve considerare questi dati
treno (<numero treno>)
nome ( <nome> <cognome>)
data ( <gg>/<mm>/ <aaaa>) ;
carrozza ( <numero carrozza> )
posto ( <numero posto> )
classe ( < 1 o 2 > )
che, come può vedere il lettore, è una struttura complessa nella quale compare una data con tre campi e un nome dell’utente che prenota composto da nome e cognome. Bisogna per tanto procedere prima a dichiarare una struttura e tipo per la data, una struttura e tipo per il nome, quindi inserirli all’interno della struttura complessiva della prenotazione. Gli altri tipi sono in formato base.
typedef struct nome_utente
{
char nome[30];
char cognome[30];
} Nome;
typedef struct data_prenotazione
{
int giorno;
int mese;
int anno;
} Data;
typedef struct prenotazione_treno
{
int treno;
Nome nome;
Data data;
int carrozza;
int posto;
int classe; //mettere una enum?
} prenotazione;
Le funzioni scritte non sono complesse prese individualmente.
inizializzaPrenotazioni semplicemente mette valori nulli nel vettore delle 100 prenotazioni. Non è obbligatorio, ma è sempre una buona idea inizializzare le variabili per non avere sorprese di dati sporchi. apriFile apre in lettura il file e carica tutti i dati che trova sul vettore principale su cui andremo a lavorare per la nuova prenotazione. salvaFile è una funzione a cui non passo tutto il vettore di lavoro: posso prenotare un solo posto per esecuzione! La cosa interessante da tenere a mente però è che il file non può essere aperto in semplice modalità write con w, ma poiché viene sempre riaperto per aggiungere prenotazioni, deve essere aperto in modalità append, con il parametro a. Il parametro w infatti sovrascriverebbe sempre la stessa riga. prenota si occupa di controllare la disponibilità di un posto sul vettore delle prenotazioni e di interagire con l’utente per l’inserimento corretto dei dati con opportuni messaggi di errore qualora termini la disponibilità di posti di una classe o si scelga un posto occupato. La funzione di visualizzazione è intuitiva, eccezione per la scelta procedurale di stampare una classe piuttosto che un’altra in basa al parametro passato. statistiche mostra semplicemente qualche percentuale sui posti occupati, in totale, di prima e seconda classe.
Il codice completo
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define POSTI 100
#define PRIMA 20
#define SECONDA 80
#define NOMEFILE "prenota_posti_treno.dat"
/* strutture dati */
typedef struct nome_utente
{
char nome[30];
char cognome[30];
} Nome;
typedef struct data_prenotazione
{
int giorno;
int mese;
int anno;
} Data;
typedef struct prenotazione_treno
{
int treno;
Nome nome;
Data data;
int carrozza;
int posto;
int classe; //mettere una enum?
} prenotazione;
/* dichiarazioni di funzioni */
void inizializzaPrenotazioni(prenotazione []);
int salvaFile(prenotazione); //qui non passo tutto il vettore: posso prenotare un solo posto per esecuizione!
int apriFile(prenotazione []);
prenotazione prenota(prenotazione []);
void visualizzaPosti(prenotazione [], int);
void statistiche(prenotazione []);
int main()
{
prenotazione p[POSTI];
prenotazione prenotazioneSingola;
inizializzaPrenotazioni(p);
apriFile(p);
visualizzaPosti(p,1);
visualizzaPosti(p,2);
statistiche(p);
prenotazioneSingola = prenota(p);
salvaFile(prenotazioneSingola);
return 0;
}
int salvaFile(prenotazione _prenotazione)
{
FILE * _file;
_file=fopen(NOMEFILE,"a"); //append, aggiunge in coda
if (!_file)
{
printf("Errore nell'apertura del file!");
return 1;
}
//scrivo un solo record in coda
//printf("%d\n",_prenotazione.posto); //debug
fwrite(&_prenotazione,sizeof(_prenotazione),1,_file);
fclose(_file);
printf("---------------------------------\n");
printf("Salvata %d prenotazione\n", 1);
printf("File scritto correttamente\n");
printf("---------------------------------\n");
return 0;
}
int apriFile(prenotazione _prenotazione[])
{
prenotazione record;
int i = 0; //contatore per scrivere/scorrere il vettore
FILE *_file;
_file=fopen(NOMEFILE,"r");
if (!_file)
{
printf("Errore nell'apertura del file!");
return 1;
}
printf("---------------------------------\n");
printf("File aperto in lettura\n");
printf("---------------------------------\n");
while (!feof(_file))
{
fread(&record,sizeof(struct prenotazione_treno),1,_file);
//printf("%d\n",record.posto); //debug
//attenzione: sovrascrivo il vettore
//i posti non corrispondono all'indice del vettore ma all'ordine di prenotazione
_prenotazione[i].treno = record.treno;
strcpy(_prenotazione[i].nome.nome,record.nome.nome );
strcpy(_prenotazione[i].nome.cognome,record.nome.cognome );
_prenotazione[i].carrozza = record.carrozza;
_prenotazione[i].posto = record.posto;
_prenotazione[i].data.giorno = record.data.giorno;
_prenotazione[i].data.mese = record.data.mese;
_prenotazione[i].data.anno = record.data.anno;
_prenotazione[i].classe = record.classe;
i++;
}
printf("---------------------------------\n");
printf("Caricate %d prenotazioni\n", i);
printf("File letto correttamente\n");
printf("---------------------------------\n");
fclose(_file);
return 0;
}
prenotazione prenota(prenotazione _p[])
{
prenotazione prenotazioneNuova;
int postiPrimaClasse, postiSecondaClasse;
int i;
int ok = 0;
printf("\n");
printf("---------------------------------\n");
printf(" Prenota \n");
printf("---------------------------------\n");
prenotazioneNuova.treno = 1001; //il numero del treno lo metto di default, è un solo treno!
printf("Inserisci i dati di prenotazione\n");
printf("Nome: ");
scanf("%s", prenotazioneNuova.nome.nome);
printf("Cognome: ");
scanf("%s", prenotazioneNuova.nome.cognome);
printf("Data: ");
scanf("%d %d %d", &prenotazioneNuova.data.giorno,&prenotazioneNuova.data.mese,&prenotazioneNuova.data.anno);
printf("Carrozza: ");
scanf("%d", &prenotazioneNuova.carrozza);
while (!ok)
{
printf("Posto: ");
scanf("%d", &prenotazioneNuova.posto);
printf("Classe (1 o 2): ");
scanf("%d", &prenotazioneNuova.classe);
ok = 1;
for (i=0; i < POSTI; i++ )
{
if (_p[i].posto == prenotazioneNuova.posto)
{
printf ("Posto già occupato. Scegli ancora");
ok = 0;
}
}
for (i=0; i < POSTI; i++ )
{
if (_p[i].classe == 1)
{
postiPrimaClasse++;
}
if (_p[i].classe == 2)
{
postiSecondaClasse++;
}
if (prenotazioneNuova.posto == 1 && postiPrimaClasse >= PRIMA )
{
printf ("Posti della prima classe esauriti. Scegli ancora\n");
ok = 0;
}
if (prenotazioneNuova.posto == 2 && postiSecondaClasse >= SECONDA )
{
printf ("Posti della seconda classe esauriti. Scegli ancora\n");
ok = 0;
}
}
}
return prenotazioneNuova;
}
void visualizzaPosti(prenotazione _p[], int _classe)
{
int i;
printf("---------------------------------\n");
printf("Posti di %d classe:\n", _classe);
printf("---------------------------------\n");
for (i=0; i < POSTI; i++)
{
if (_p[i].classe == _classe)
{
printf("Treno: %d\n",_p[i].treno);
printf("Nome e Cognome: %s %s\n", _p[i].nome.nome,_p[i].nome.cognome);
printf("Data: %d/%d/%d\n", _p[i].data.giorno,_p[i].data.mese,_p[i].data.anno);
printf("Carrozza: %d\n",_p[i].carrozza);
printf("Posto: %d\n",_p[i].posto);
printf("Classe: %d\n",_p[i].classe);
printf("---------------------------------\n");
}
}
}
void inizializzaPrenotazioni(prenotazione _p[])
{
int i;
for (i=0; i < POSTI; i++)
{
_p[i].data.giorno = 0;
_p[i].data.mese = 0;
_p[i].data.anno = 0;
_p[i].treno = 0;
_p[i].carrozza = 0;
_p[i].posto = 0;
_p[i].classe = 0;
}
}
void statistiche(prenotazione _p[])
{
int i;
int postiOccupati = 0;
int postiPrimaClasse = 0;
int postiSecondaClasse = 0;
float primaper,secondaper, percentuale;
for (i=0; i < POSTI; i++ )
{
if (_p[i].classe == 1)
{
postiPrimaClasse++;
postiOccupati++;
}
if (_p[i].classe == 2)
{
postiSecondaClasse++;
postiOccupati++;
}
}
percentuale = (float)postiOccupati / (float)POSTI * 100;
primaper = (float)postiPrimaClasse / (float)postiOccupati * 100;
secondaper = (float)postiSecondaClasse / (float)postiOccupati * 100;
printf("Occupati %d posti su %d\n", postiOccupati, POSTI);
printf("1° classe %d posti\n", postiPrimaClasse);
printf("2° classe %d posti\n", postiSecondaClasse);
printf("Percentuale posti occupati %.2f\%\n",percentuale);
printf("Percentuale posti 1° classe %.2f\%\n",primaper);
printf("Percentuale posti 2° classe %.2f\%\n",secondaper);
}
Ultima modifica 10 Novembre 2023