Esercizio 25C, ordini della focacceria (coda)
In questa pagina 4
Testo (scritto del 16/06/2025, parte 3, in C). Gestione degli ordini alla Focacceria. Svolgi il seguente esercizio sviluppando le funzioni richieste in C. I prototipi delle funzioni non possono essere modificati; durante l'esame non è possibile consultare appunti o materiale didattico, ma è consentito usare la documentazione di Linux con man.
Una focacceria usa una coda (Queue, FIFO) per memorizzare gli ordini in arrivo. Ogni elemento della coda è un singolo ordine di focaccia. Le funzioni di base della coda (enqueue, dequeue, isEmpty) sono già implementate. Il proprietario vuole sapere quanto incassa, l'ammontare dell'invenduto in un giorno di lavoro e quante focacce avanzano. Strutture fornite:
typedef struct ordine {
char nome_cliente[64];
int tipo_focaccia; // 0: Specialità del giorno, 1: Prosciutto e funghi, 2: Vegetariana
} Ordine;
typedef struct node { Ordine data; struct node *next; } Node;
typedef struct { Node *testa; Node *coda; } Coda;
typedef struct giornata {
double incasso; // incasso totale della giornata
double invenduto; // valore delle focacce invendute
int focacce_rimaste[3]; // focacce rimaste per ciascun tipo
} Giornata;Funzioni da implementare:
void processaOrdini(Coda *coda, Giornata *giornata, double listino_prezzi[]): processa gli ordini nella coda, aggiornando l'incasso lordo e le focacce rimaste per ogni tipo. Pseudocodice: ripeti:ordine <- dequeue(coda);id <- ordine.tipo_focaccia; segiornata.focacce_rimaste[id] > 0alloragiornata.incasso <- giornata.incasso + listino_prezzi[id]egiornata.focacce_rimaste[id] <- giornata.focacce_rimaste[id] - 1; finchéisEmpty(coda).void calcolaInvenduto(Giornata *giornata, double listino_prezzi[]): calcola il profitto non realizzato a causa del cibo invenduto. Pseudocodice:for i = 0 to 2:giornata.invenduto <- giornata.invenduto + giornata.focacce_rimaste[i] * listino_prezzi[i].
Lo pseudocodice non è codice C completo (tipi, puntatori, operatore ->); si possono definire funzioni ausiliarie.
Richiami
Coda FIFO realizzata con una lista a due puntatori (testa per estrarre, coda per inserire), vedi Liste concatenate in CLista singolarmente concatenata in C con nodo struct e testa passata per riferimento (Nodo **); addHead, addTail ricorsiva e iterativa, pop, inversione in loco, liberazione; coda con puntatori a testa e coda; ricorsione sulle liste; costi.Liste concatenate in C →; passaggio di strutture per puntatore (Giornata *) e operatore ->, vedi Puntatori, struct e memoria dinamica in CPuntatori e passaggio per riferimento in C, array e aritmetica dei puntatori, stringhe, struct e typedef con l'operatore ->, malloc e free, puntatore a puntatore per modificare una testa; compilazione con Makefile; errori tipici (puntatori pendenti, perdite di memoria, off-by-one).Puntatori, struct e memoria dinamica in C →.
Soluzione
void processaOrdini(Coda *coda, Giornata *giornata, double listino_prezzi[]) {
while (!isEmpty(coda)) {
Ordine ordine = dequeue(coda);
int id = ordine.tipo_focaccia;
if (giornata->focacce_rimaste[id] > 0) {
giornata->incasso += listino_prezzi[id];
giornata->focacce_rimaste[id]--;
}
}
}
void calcolaInvenduto(Giornata *giornata, double listino_prezzi[]) {
for (int i = 0; i < 3; i++)
giornata->invenduto += giornata->focacce_rimaste[i] * listino_prezzi[i];
}Scelte da notare.
- Lo pseudocodice ripeti-finché esegue
dequeuealmeno una volta anche con la coda vuota, edequeuesu una coda vuota è un errore. Conwhile (!isEmpty(coda))il controllo precede l'estrazione e la funzione è corretta anche per la coda vuota. - Gli ordini per un tipo esaurito vengono estratti dalla coda ma non fanno incassare né diminuire la scorta (il cliente se ne va).
giornataè un puntatore:giornata->incassomodifica la struttura del chiamante (side effect), mentrelistino_prezzi[]è un array passato come puntatore (non viene modificato).- Il tipo
tipo_focacciaè usato come indice difocacce_rimastee dilistino_prezzi: . calcolaInvendutosomma nell'invenduto: se è chiamata due volte lo conta due volte (il testo parte dainvenduto = 0).- Complessità:
processaOrdiniper ordini in coda (ognidequeueè );calcolaInvenduto.
Prova eseguita
Prezzi , , ; scorte ; ordini per tipo, in coda: .
- Ordine : venduto (; scorte ). Ordine : venduto (; scorte ). Ordine : esaurita, ignorato. Ordine : venduto (; scorte ). Ordine : venduto (; ). Ordine : esaurita, ignorato. Ordine : venduto (; ).
- Incasso: ; rimaste ; invenduto . Il programma stampa
incasso=16.70 invenduto=3.20 rimaste=0 0 1. - Con la coda vuota e scorte : incasso , invenduto ✓.
Errori comuni
- Usare
giornata.incassocon il punto invece di->(il parametro è un puntatore). do { dequeue } while (...)come nello pseudocodice: errore con la coda vuota.- Decrementare la scorta anche quando è già zero (scorta negativa) o incassare gli ordini non soddisfatti.
- Dimenticare
doubleper i prezzi e dividere/moltiplicare con interi. - Cercare di conservare un puntatore al nodo estratto:
dequeuelibera il nodo e restituisce l'Ordineper valore, quindi basta usare la copia restituita.
Versione ripasso
Testo. Coda FIFO di ordini (tipo_focaccia ), Giornata con incasso, invenduto, focacce_rimaste[3]. Implementare processaOrdini(Coda*, Giornata*, double[]) e calcolaInvenduto(Giornata*, double[]) in C.
- processaOrdini (vedi Liste concatenate in CLista singolarmente concatenata in C con nodo struct e testa passata per riferimento (Nodo **); addHead, addTail ricorsiva e iterativa, pop, inversione in loco, liberazione; coda con puntatori a testa e coda; ricorsione sulle liste; costi.Liste concatenate in C →):
while (!isEmpty(coda)):ordine = dequeue(coda); sefocacce_rimaste[id] > 0:incasso += listino_prezzi[id]efocacce_rimaste[id]--. Con la coda vuotaripeti-finchédello pseudocodice sbaglierebbe. - calcolaInvenduto:
for i in 0..2: invenduto += focacce_rimaste[i] * listino_prezzi[i]. - Dettagli:
giornataper puntatore (->); ordini per tipo esaurito ignorati; e . - Prova: prezzi , scorte , ordini ⇒ incasso , rimaste , invenduto .
- Codice:
while (!isEmpty(coda)) { Ordine o = dequeue(coda); int id = o.tipo_focaccia; if (giornata->focacce_rimaste[id] > 0) { giornata->incasso += listino_prezzi[id]; giornata->focacce_rimaste[id]--; } };calcolaInvenduto:for (i = 0; i < 3; i++) giornata->invenduto += giornata->focacce_rimaste[i] * listino_prezzi[i];. - Verifica: scorte e ordini : vendute focacce (), le altre due ordinazioni (tipi e ) trovano la scorta finita; coda vuota ⇒ incasso , invenduto .
- Errori:
.invece di->;do-whilesu coda vuota; scorta negativa; puntatore a un nodo già liberato.