Formula 1, Campionato - Soluzione
In questo tutorial non verrà presentata la possibile soluzione nella sua interezza, ma soltano le parti interessanti, che dovranno essere opportunamente integrate per fornire la soluzione completa e compilabile.
Per ottenere un programma completo e funzionante, si tratta pertanto di scrivere la funzione main
che dichiara le variabili necessarie e che chiama opportunamente le funzioni descritte.
Per cominciare, si assume che vengano effettuate le seguenti dichiarazioni:
#define N_SQUADRE (10)
#define N_PILOTI (20)
#define MAX_RIGA (50)
#define POS_A_PUNTI (10) /* Posizioni a cui si assegnano punti */
int punti_per_pos[POS_A_PUNTI] = {
25, 18, 15, 12, 10, 8, 6, 4, 2, 1
};
I dati saranno memorizzati in array di strutture. Piloti e squadre richiedono lo stesso tipo di informazioni (nome e punteggio). Pertanto conviene utilizzare lo stesso tipo, in questo modo si eviterà di replicare le funzioni che effettuano le elaborazioni:
struct classificato {
char nome[MAX_RIGA + 1];
int punti;
};
Le funzioni descritte di seguito dovranno essere oppotunamente richiamate nel main
.
Ad esse dovranno essere passati gli argomenti corretti.
Lettura del file
La funzione per la lettura e l'elaborazione del file può essere come segue:
int leggi_gara(FILE * fin,
struct classificato *piloti,
struct classificato *scuderie)
{
char buffer[MAX_RIGA + 1];
int pos, punti;
char nome_pilota[MAX_RIGA + 1];
char nome_scuderia[MAX_RIGA + 1];
pos = 0;
while (pos < N_PILOTI && fgets(buffer, MAX_RIGA + 1, fin) != NULL) {
sscanf(buffer, "%s %s", nome_pilota, nome_scuderia);
if (pos < POS_A_PUNTI)
punti = punti_per_pos[pos];
else
punti = 0;
/* Cerca il pilota nell'elenco e gli assegna i punti. */
struct classificato *pilota =
cerca_classificato(piloti, N_PILOTI, nome_pilota);
pilota->punti += punti;
/* Cerca la squadra nell'elenco e gli assegna i punti. */
struct classificato *scuderia =
cerca_classificato(scuderie, N_SQUADRE,
nome_scuderia);
scuderia->punti += punti;
/* Passaggio alla posizione successiva. */
pos++;
}
return pos;
}
La funzione legge al massimo N_PILOTI
righe dal file, corrispondenti al numero di piloti che partecipano ad una sola gara, quindi ad ogni chiamata vengono letti i dati di una sola gara.
Questo significa che deve essere chiamata più volte per leggere tutti i dati dal file, cosa che essere fatta in questo modo:
while (leggi_gara(fin, piloti, scuderie) != 0) {
/* quando leggi_gara ritorna, una gara intera e` stata letta */
.....
}
La funzione richiede due argomenti:
- il file da leggere, già aperto in lettura prima di chiamare
leggi_gara
(S8.2.1); - il vettore
piloti
di strutture di tipostruct classificato
per memorizzare i punteggi dei piloti, passato per riferimento (S6.6).
Inoltre: il ciclo while
viene eseguito finché si registra il risultato di tutti i piloti attesi (pos < N_PILOTI
) e, contemporaneamente, finché ci sono righe nel file.
Ricorda che fgets
restituisce NULL
(quindi 0
, quindi "falso") quando si è giunti alla fine del file e non ci sono più righe da leggere (S8.6).
Per scrivere il nome del pilota nel campo della struttura va usata la strcpy
, perché l'assegnamento (operatore =
) non funziona con le stringhe (S5.11).
ATTENZIONE: l'istruzione che memorizza i punti del pilota è un incremento, quindi questa funzione si aspetta che il valore dei punti sia correttamente inizializzato a zero!
Ricerca di un elemento nel vettore di piloti e scuderie
La leggi_gara
usa la funzione cerca_classificato
per farsi restituire l'elemento del vettore del quale aggiornare il punteggio.
Questo viene fatto due volte: per il vettore piloti
e per il vettore scuderie
.
La funzione cerca_classificato
è la stessa in entrambi i casi, in quanto opera sempre su vettori di tipo struct classificato
, nel quale cerca il generico elemento il cui campo nome
sia uguale al nome specificato.
La funzione cerca_classificato
può essere formulata come segue:
struct classificato *cerca_classificato(
struct classificato *elenco,
int size,
char *nome)
{
int i;
for (i = 0; i < size; i++) {
if (strcmp(elenco[i].nome, nome) == 0)
return &elenco[i]; /* Trovato */
if (elenco[i].nome[0] == '\0') {
/* Trovato un record vuoto, da inizializzare
con il nome prima di restituirlo. */
strcpy(elenco[i].nome, nome);
elenco[i].punti = 0;
return &elenco[i];
}
}
/* Non si dovrebbe mai arrivare qui. */
return NULL;
}
Alcune delle sue peculiarità:
- la funzione cerca nel vettore
elenco
l'elemento il cui camponome
corrisponde alla stringanome
passata come terzo argomento; - il vettore
elenco
ha dimensione pari asize
elementi; - il ciclo
for
esamina i vari elementi del vettoreelenco
; - usa la
strcmp
per confrontarenome
conelenco[i].nome
, che è il camponome
dell'elemento i-esimo del vettore; - se la
strcmp
restituisce0
vuol dire che l'elemento è stato trovato, e ne viene restituito l'indirizzo;
Se nel ciclo viene raggiunto un elemento il cui campo nome
è la stringa vuota, allora questo elemento viene inizializzato come segue:
- nel campo
nome
viene copiata la stringanome
(constrcpy
); - il campo
punti
viene inizializzato a zero; - viene restituito l'indirizzo di questo elemento.
Il funzionamento di cerca_classificato
implica che gli elementi del vettore elenco
siano stati tutti inizializzati con una funzione come la seguente:
void inizializza_elenco(struct classificato *elenco, int size)
{
int i;
for (i = 0; i < size; i++)
elenco[i].nome[0] = '\0';
}
1) Numero di gare
Per come è strutturato il programma, per conoscere il numero di gare è sufficiente contare - nel main
- il numero di volte che viene chiamata la funzione leggi_gara
, per esempio come segue:
int nGare = 0;
while (leggi_gara(fin, piloti, scuderie) != 0) {
/* quando leggi_gara ritorna, una gara intera e` stata letta */
nGare++;
}
2) Pilota vincitore
La ricerca del pilota vincitore può essere svolta con una funzione come la seguente:
int cerca_vincitore(struct classificato *elenco, int size) {
int vincitore = 0, i;
for (i = 1; i < size; i++) {
if (elenco[i].punti > elenco[vincitore].punti)
vincitore = i;
/*
* se due piloti hanno lo stesso punteggio vince chi viene prima
* in ordine alfabetico
*/
else if (elenco[i].punti == elenco[vincitore].punti &&
strcmp(elenco[i].nome, elenco[vincitore].nome)< 0)
vincitore = i;
}
return vincitore;
}
La funzione ricerca nel vettore elenco
l'indice dell'elemento che ha il valore del campo punti
più elevato.
L'indice potrà essere usato per recuperare il nome del vincitore nel vettore piloti
.
Per gestire il caso in cui due elementi abbiano lo stesso numero di punti, viene usata la funzione strcmp
per determinare se un nome viene prima dell'altro, e viene mantenuto l'indice opportuno.
Ricorda che la strcmp
restituisce:
0
se le due stringhe sono uguali- un valore minore di zero se la prima stringa viene prima in ordine alfabetico rispetto alla seconda
- un valore maggiore di zero viceversa
La funzione andrà richiamata passandole come primo argomento il vettore piloti
riempito dalle chiamate alla funzione leggi_gara
illustrata precedentemente.
Per esempio:
pilota_vinc = cerca_vincitore(piloti, N_PILOTI);
Attenzione alla dimensione del vettore, che in questo caso è pari a N_PILOTI
.
3) Squadra vincitrice
L'individuazione della scuderia vincente avviene come per il pilota, usando la funzione cerca_vincitore
illustrata precedentemente.
Verrà richiamata però passandogli il vettore dei punti delle squadre, per esempio come segue:
scuderia_vinc = cerca_vincitore(scuderie, N_SQUADRE);
Attenzione alla dimensione del vettore, che in questo caso è pari a N_SQUADRE
.