Stazione di monitoraggio 2
..:: Versione con numero di righe calcolabile a priori ::..
Un dispositivo di rilevazione misura diversi parametri ambientali per mezzo di sensori. I dati misurati vengono memorizzati in un file insieme all'istante temporale nel quale sono rilevati (detto, in gergo, timestamp).
Ciascuna riga del file ha il seguente formato:
AAAA-MM-GG hh:mm:ss.ms ID TEMP UMID VEL
Il significato dei diveri elementi è riportato nella seguente tabella.
Valore | Significato | Tipo | Intervallo/dimensione |
---|---|---|---|
AAAA | anno | intero | |
MM | mese | intero | [1..12] |
GG | giorno | intero | [1..31] |
hh | ore | intero | [0..23] |
mm | minuti | intero | [0..59] |
ss | secondi | intero | [0..59] |
ms | millisecondi | intero | [0..999] |
ID | identificativo del dispositivo | stringa | max 10 caratteri |
TEMP | temperatura [gradi] | float | |
UMID | umidità [%] | intero | [0..100] |
VEL | velocità del vento [m/s] | float | >= 0 |
Un esempio di contenuto del file è il seguente:
2019-03-03 23:59:10.120 R101 17.5 20% 0.4
2019-03-02 07:41:59.001 X023 16.9 22% 0.2
2019-03-01 12:10:00.000 X023 22.5 21% 0.3
...
Scrivere un programma che legga il file nel formato illustrato e stampi a video i valori richiesti nei seguenti quesiti.
IMPORTANTE: per questo tutorial si assuma che il file contenga i dati di un solo dispositivo. Le misurazioni vengono effettuate nell'arco di una settimana esatta, una volta ogni ora.
Suggerimenti generali
Si vedrà che in questo tutorial è richiesto il calcolo di un risultato che richiede di caricare in memoria tutti i dati prima di elaborarli.
Per fare questo, il metodo più comodo è quello di utilizzare un vettore di strutture, e poi elaborare i dati presenti nel vettore. Un esempio di struttura è la seguente:
struct misura {
/* opportuni campi */
};
Ciascuna struttura conterrà i dati di una riga. Per poter utilizzare un vettore, bisogna dichiararlo, e per farlo bisogna conoscerne la dimensione.
Il testo del problema permette di calcolare la dimensione del vettore. Infatti, se le misurazioni provengono da un dispositivo soltanto, e si effettua una misurazione all'ora per una settimana, il numero di righe presenti nel file sarà pari a:
n = (# dispositivi) * (ore/giorno) * (giorni/settimana)
ovvero
n = 1 * 24 * 7 = 168
1) Stampa invertita
Si stampino le prime 3 righe e le ultime 3 righe del file. Le ultime 3 righe vengano stampate in ordine inverso, partendo dall'ultima riga presente nel file fino alla terz'ultima.
Il formato delle singole righe sia identico a quello del file di input.
[INVERTITA]
riga_prima
riga_seconda
riga_terza
riga_ultima
riga_penultima
riga_terzultima
Se nel file sono complessivamente presenti meno di 6 righe, le si stampi tutte in ordine invertito, ovvero dall'ultima alla prima.
Suggerimenti generali
Dovendo stampare i dati in ordine inverso, conviene prima caricare in memoria tutti i dati. Per fare questo:
- realizzare un ciclo di lettura utilizzando
fgets
esscanf
(vedi S8.6)
Il nome del file da leggere sarà l'argomento argv[1]
del main
(vedi S6.9), mentre per aprire il file in lettura con fopen
(S8.2.1).
Funzione di lettura
La parte principale dell'elaborazione viene fatta durante la lettura del file. Quando viene letta una riga, questa viene elaborata per estrarre e memorizzare i dati letti.
Si può creare una funzione di lettura dichiarata come la segue:
void leggi_file(FILE *f, struct misura *elenco, int *n);
La funzione richiede tre argomenti:
- il file da leggere, già aperto in lettura prima di chiamare
leggi_file
(S8.2.1) - un puntatore all'elenco di stutture
struct misura
da leggere, all'interno del quale caricare i dati letti - un puntatore a intero
int
per restituire, tramite passaggio del parametro per indirizzo (S6.6), il numero di dati effettivamente letti
Viste le assunzioni fatte sul contenuto del file, il numero di elementi letti è calcolabile a priori. Quindi il numero di dati effettivamente letti potrebbe non servire tra gli argomenti della funzione di lettura. In questo caso si è scelto di prevederne la restituzione del valore per una maggiore generalità della soluzione.
Nella funzione leggi_file
:
- il file può essere letto con un ciclo attraverso
fgets
(S8.6) - da ogni riga, si estraggono i dati tramite
sscanf
;- ricorda che per estrarre una stringa con
sscanf
si usa lo specificatore%s
(S8.6! - nella
sscanf
, la variabile stringa nella quale memorizzare il nome estratto va passato per riferimento (e visto che si tratta di un vettore dichar
non serve la&
)
- ricorda che per estrarre una stringa con
Nel main
:
- bisogna chiamare la funzione
leggi_file
2) Massima temperatura
Determinare la temperatura massima tra tutte quelle misurate, indicata con max_temp
, e stamparne a video il valore con il seguente formato:
[MAX-TEMP]
max_temp
Suggerimenti generali
In questo caso, si assume che i dati siano stati caricati in un vettore come spiegato nel punto (1).
È possibile modificare la funzione di lettura implementata al punto precedente per tenere traccia del valore massimo letto, e stamparne il valore al termine della lettura.
Verifica manuale
La verifica del funzionamento del programma può essere fatta manualmente, utilizzando il file di input file2.txt come esempio, richiamando l'eseguibile come segue:
./a.out file2.txt
Verifica automatica
Si può utilizzare il tool pvcheck
di verifica automatica per testare il corretto funzionamento del programma (maggiori informazioni circa l'uso di pvcheck
sono disponibili qui).
Il file contenente i test è misure2.test.
Il comando da eseguire per il test è il seguente:
pvcheck -f misure2.test ./a.out
Nella prossima pagina potrai esaminare un esempio di soluzione dell'esercizio.