Salta al contenuto
Note per Studenti Esercizio 25 · C, ordini della focacceria (coda)

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:

c
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; se giornata.focacce_rimaste[id] > 0 allora giornata.incasso <- giornata.incasso + listino_prezzi[id] e giornata.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

c
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 dequeue almeno una volta anche con la coda vuota, e dequeue su una coda vuota è un errore. Con while (!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->incasso modifica la struttura del chiamante (side effect), mentre listino_prezzi[] è un array passato come puntatore (non viene modificato).
  • Il tipo tipo_focaccia è usato come indice di focacce_rimaste e di listino_prezzi: 0,1,20, 1, 2.
  • calcolaInvenduto somma nell'invenduto: se è chiamata due volte lo conta due volte (il testo parte da invenduto = 0).
  • Complessità: processaOrdini Θ(n)\Theta(n) per nn ordini in coda (ogni dequeue è Θ(1)\Theta(1)); calcolaInvenduto Θ(1)\Theta(1).

Prova eseguita

Prezzi 3,43{,}4, 3,53{,}5, 3,23{,}2; scorte (2,1,3)(2, 1, 3); ordini per tipo, in coda: 0,1,1,0,2,0,20, 1, 1, 0, 2, 0, 2.

  • Ordine 00: venduto (3,43{,}4; scorte 1,1,31, 1, 3). Ordine 11: venduto (3,53{,}5; scorte 1,0,31, 0, 3). Ordine 11: esaurita, ignorato. Ordine 00: venduto (3,43{,}4; scorte 0,0,30, 0, 3). Ordine 22: venduto (3,23{,}2; 0,0,20, 0, 2). Ordine 00: esaurita, ignorato. Ordine 22: venduto (3,23{,}2; 0,0,10, 0, 1).
  • Incasso: 3,4+3,5+3,4+3,2+3,2=16,703{,}4 + 3{,}5 + 3{,}4 + 3{,}2 + 3{,}2 = 16{,}70; rimaste (0,0,1)(0, 0, 1); invenduto 1⋅3,2=3,201 \cdot 3{,}2 = 3{,}20. Il programma stampa incasso=16.70 invenduto=3.20 rimaste=0 0 1.
  • Con la coda vuota e scorte (1,1,1)(1, 1, 1): incasso 00, invenduto 3,4+3,5+3,2=10,103{,}4 + 3{,}5 + 3{,}2 = 10{,}10 ✓.

Errori comuni

  • Usare giornata.incasso con 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 double per i prezzi e dividere/moltiplicare con interi.
  • Cercare di conservare un puntatore al nodo estratto: dequeue libera il nodo e restituisce l'Ordine per valore, quindi basta usare la copia restituita.

Versione ripasso

Testo. Coda FIFO di ordini (tipo_focaccia 0,1,20, 1, 2), 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); se focacce_rimaste[id] > 0: incasso += listino_prezzi[id] e focacce_rimaste[id]--. Con la coda vuota ripeti-finché dello pseudocodice sbaglierebbe.
  • calcolaInvenduto: for i in 0..2: invenduto += focacce_rimaste[i] * listino_prezzi[i].
  • Dettagli: giornata per puntatore (->); ordini per tipo esaurito ignorati; Θ(n)\Theta(n) e Θ(1)\Theta(1).
  • Prova: prezzi 3,4/3,5/3,23{,}4/3{,}5/3{,}2, scorte (2,1,3)(2,1,3), ordini 0,1,1,0,2,0,20,1,1,0,2,0,2 ⇒ incasso 16,7016{,}70, rimaste (0,0,1)(0,0,1), invenduto 3,203{,}20.
  • 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 (2,1,3)(2,1,3) e ordini 0,1,1,0,2,0,20,1,1,0,2,0,2: vendute 55 focacce (3,4+3,5+3,4+3,2+3,2=16,703{,}4 + 3{,}5 + 3{,}4 + 3{,}2 + 3{,}2 = 16{,}70), le altre due ordinazioni (tipi 11 e 00) trovano la scorta finita; coda vuota ⇒ incasso 00, invenduto 10,1010{,}10.
  • Errori: . invece di ->; do-while su coda vuota; scorta negativa; puntatore a un nodo già liberato.

Teoria collegata