Esercizio 29C, centralina meteo (lista ordinata)
In questa pagina 4
Testo (secondo appello 2025-26, luglio 2026, parte 3, in C). Centralina meteo del laboratorio. 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; è consentito utilizzare la documentazione Linux con man.
Nel laboratorio di elettronica è stata installata una piccola centralina che registra una misura di temperatura ogni volta che uno studente avvia un test. Le misure arrivano in ordine non garantito, ma il software deve conservarle in una lista ordinata per minuto di acquisizione. Ogni misura è rappresentata da:
typedef struct reading { int minute; double temperature; } Reading;
typedef struct node { Reading data; struct node *next; } Node;Il campo minute indica il minuto dall'inizio dell'esperimento; temperature la temperatura in gradi Celsius. Funzioni da completare:
Node *insertSorted(Node *log, Reading reading): inserisce una nuova rilevazione nella lista, mantenendo i nodi ordinati in modo crescente rispetto aminute. Deve allocare dinamicamente un nuovo nodo e restituire la nuova testa della lista.int removeOutOfRange(Node **log, double minTemperature, double maxTemperature): rimuove dalla lista tutte le rilevazioni con temperatura minore diminTemperatureo maggiore dimaxTemperature. Deve aggiornare la testa quando vengono rimossi i primi nodi, liberare la memoria dei nodi eliminati e restituire il numero di rilevazioni rimosse.double averageTemperatures(Node *log): calcola la media aritmetica delle temperature presenti nel registro. Se la lista è vuota restituisce .int countReadingsAboveThreshold(Node *log, double threshold): conta quante rilevazioni hanno temperatura strettamente maggiore dithreshold. Se la lista è vuota restituisce .
Indicazioni: la lista è semplicemente concatenata; si possono definire funzioni ausiliarie; non modificare main() e le funzioni di test. Esempio: inserendo le misure , e la lista finale deve avere i minuti nell'ordine . Se in una lista sono presenti temperature , , e , con soglie e devono essere rimossi i nodi con temperature e .
Richiami
Liste concatenate e puntatore a puntatore (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 → e 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 →). Si usa il modello "puntatore al puntatore da modificare" (Node **p), che tratta uniformemente testa e nodi intermedi.
Soluzione
Node *insertSorted(Node *log, Reading reading) {
Node *n = malloc(sizeof(Node));
n->data = reading;
Node **p = &log; /* p: indirizzo del puntatore da modificare */
while (*p != NULL && (*p)->data.minute <= reading.minute)
p = &(*p)->next; /* si ferma al primo minuto maggiore */
n->next = *p;
*p = n;
return log;
}
int removeOutOfRange(Node **log, double minTemperature, double maxTemperature) {
int removed = 0;
Node **p = log;
while (*p != NULL) {
double t = (*p)->data.temperature;
if (t < minTemperature || t > maxTemperature) {
Node *dead = *p;
*p = dead->next; /* scollega (anche la testa) */
free(dead);
removed++;
} else
p = &(*p)->next;
}
return removed;
}
double averageTemperatures(Node *log) {
double sum = 0.0;
int n = 0;
for (; log != NULL; log = log->next) {
sum += log->data.temperature;
n++;
}
return n == 0 ? 0.0 : sum / n;
}
int countReadingsAboveThreshold(Node *log, double threshold) {
int c = 0;
for (; log != NULL; log = log->next)
if (log->data.temperature > threshold)
c++;
return c;
}Idea del puntatore a puntatore. p contiene l'indirizzo del puntatore che punta al nodo corrente: all'inizio è &log (la testa), poi diventa &(*p)->next (il campo next del nodo precedente). Inserire o togliere significa scrivere in *p, e funziona allo stesso modo per la testa e per un nodo qualsiasi: non servono casi speciali (lista vuota, inserimento in testa, rimozione della testa).
Dettagli.
insertSortedusa<=nel confronto: una misura con un minuto già presente viene messa dopo quelle con lo stesso minuto (inserimento stabile). Con<andrebbe prima: il testo non lo specifica, vanno bene entrambe purché la lista resti ordinata in modo non decrescente.- Nella rimozione si legge
dead->nextprima difree(dead); dopo lafreeil nodo non si deve più usare. Dopo una rimozionepnon avanza (il nodo successivo è ora in*p); avanza solo se il nodo resta. averageTemperaturesdivide pernsolo se ; la somma èdouble, quindi nessuna divisione intera.- Complessità:
insertSorted(scorre fino al punto di inserimento, se va in testa);removeOutOfRange,averageTemperatures,countReadingsAboveThreshold.
Prove eseguite
- Inserimenti , , e : lista
(10, 20.5) (20, 21.0) (20, 25.0) (30, 22.0)(minuti ordinati; il secondo dopo il primo). - Temperature , , , ai minuti , soglie e : rimossi nodi, restano e ; media ; sopra : .
- Con soglie e su quella lista: rimossi (testa e coda), lista vuota; media e conteggio ✓.
Errori comuni
- Passare
Node *logaremoveOutOfRange(il prototipo haNode **): se si rimuove la testa il chiamante non lo vede. - In
insertSortednon gestire l'inserimento in testa o in lista vuota: con il puntatore a puntatore il caso è automatico. - Fare
free(dead)e poi leggeredead->next. - Avanzare
pdopo una rimozione (si salta un nodo). - Dividere per nella media con lista vuota (serve il controllo ).
- Dimenticare
>stretto incountReadingsAboveThreshold(la soglia stessa non conta).
Versione ripasso
Testo. Lista di Reading { int minute; double temperature; } ordinata per minuto; implementare insertSorted (restituisce la nuova testa), removeOutOfRange(Node **, min, max) (libera i nodi, restituisce quanti), averageTemperatures ( se vuota), countReadingsAboveThreshold (stretto).
- Modello
Node **p(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 →):p = &logo&(*p)->next; scrivere in*pvale per testa e nodi intermedi. - insertSorted:
while (*p && (*p)->data.minute <= reading.minute) p = &(*p)->next; n->next = *p; *p = n;. - removeOutOfRange: se fuori soglia:
dead = *p; *p = dead->next; free(dead); removed++(senza avanzare), altrimenti avanza. - Media e conteggio: scansione; media
0.0se ;>stretto. - Costi: tutte (inserimento ).
- Prove: minuti ; con soglie e ⇒ rimossi, media , sopra : .
- Codice:
insertSorted:Node **p = &log; while (*p && (*p)->data.minute <= reading.minute) p = &(*p)->next; n->next = *p; *p = n; return log;;removeOutOfRange: fuori soglia ⇒dead = *p; *p = dead->next; free(dead); removed++;altrimentip = &(*p)->next. - Media: con , altrimenti ; conteggio con
>stretto. Prove: minuti ; con soglie e ⇒ rimossi, media . - Modello
Node **p:p= indirizzo del puntatore da modificare (&log, poi&(*p)->next): inserimento e rimozione valgono per testa e nodi intermedi senza casi speciali. Stesso minuto: con<=la nuova misura va dopo. - Errori:
Node *al posto diNode **;freeprima di leggerenext; avanzare dopo una rimozione; divisione per .