Esercizio 1
Scrivere un programma C che legge da tastiera una sequenza di numeri reali; la lettura
termina quando la somma dei numeri immessi è maggiore di 50, e comunque non si possono
immettere più di 100 numeri (se anche dopo avere immesso 100 numeri la loro somma non
supera 50 la lettura termina comunque). Dopo avere letto tutti i numeri, se l’utente ha inserito
almeno 3 valori, cercare se esiste una coppia di numeri tali che il loro rapporto (o il suo
inverso) sia uguale al primo numero immesso e, se esiste, stamparla.
Esempio di funzionamento del programma:
Inserisci numero: 6.25
Inserisci numero: -2.5
Inserisci numero: 20
Inserisci numero: 13.863
Inserisci numero: -15.625
Inserisci numero: 4
Inserisci numero: 38.192
Il rapporto (o il suo inverso) tra -2.5 e -15.625 vale 6.25.
Soluzione
#include <stdio.h>
typedef enum{false, true} bool;
#define MAX_NUM 100
#define MAX_SUM 50
#define TOL 0.00000001
main(){
float dati[MAX_NUM], sum = 0, rapp, inv_rapp;
int i, j, n_dati;
bool trovata = false;
n_dati = 0;
do {
printf("Inserisci numero: ");
scanf("%f", &dati[n_dati]);
sum += dati[n_dati];
n_dati++;
} while (sum <= MAX_SUM && n_dati < MAX_NUM);
if (n_dati >= 3) {
i = 1;
while (!trovata && i<n_dati-1) {
j = i+1;
while (!trovata && j<n_dati) {
if (dati[i] == 0 || dati[j] == 0) {
if (dati[0] == 0) {
trovata = true;
}
} else {
rapp = dati[i]/dati[j];
inv_rapp = dati[j]/dati[i];
if (rapp - dati[0] < TOL && rapp - dati[0] > -TOL ||
inv_rapp - dati[0] < TOL && inv_rapp - dati[0] > -TOL) {
trovata = true;
}
}
if (trovata == true) {
printf(“Il rapporto (o il suo inverso) tra %f e %f vale
%f\n”,
dati[i], dati[j], dati[0]);
}
j++;
}
i++;
}
} else {
printf(“Sono stati inseriti solo %d elementi\n”, n_dati);
}
}
Esercizio 2
Si vogliono definire i tipi di dato che servono per contenere le informazioni di un pubblico
registro automobilistico dedicato ai motoveicoli. I tipi da definire sono i seguenti.
TipoDatiMotoveicolo rappresenta i dati di un motoveicolo. Questi dati si compongono
di: targa del motoveicolo (7 lettere), marca del motoveicolo (massimo 15 caratteri), modello
(massimo 20 caratteri), cilindrata (in cc), potenza (in kW), categoria (motorino, scooter,
motocicletta, motocarro).
TipoDatiProprietario rappresenta i dati di una persona (il proprietario del
motoveicolo): nome (massimo 30 caratteri), cognome (massimo 40 caratteri), codice fiscale
(16 caratteri).
TipoVocePRA rappresenta una singola voce nel registro automobilistico; una voce si
compone di 2 elementi, i dati del proprietario del motoveicolo ed i dati del motoveicolo
stesso.
TipoPRA rappresenta un tipo adatto a contenere i dati di un PRA. Questo tipo di dati è un
elenco di voci del PRA (si suppone che un PRA non possa contenere più di 10.000 elementi),
più un contatore che dice quante voci sono effettivamente presenti nel PRA.
(se si ritiene utile, si possono definire altri tipi di dati, di supporto a quelli richiesti)
Soluzione
typedef enum {motorino, scooter, motocicletta, motocarro}
TipoCategoria;
typedef struct {
char targa[7]
char marca[15]
char modello[20]
int cilindrata;
float potenza;
TipoCategoria categoria;
} TipoDatiMotoveicolo;
typedef struct {
char nome[30];
char cognome[40];
char codice_fiscale[16];
} TipoDatiProprietario;
typedef struct {
TipoDatiMotoveicolo motoveicolo;
TipoDatiProprietario proprietario;
} TipoVocePRA;
typedef struct {
TipoVocePRA elementi[10000];
int n_elementi;
} TipoPRA;
Esercizio 3
Siano P, Q, R, tre puntatori a interi e x, y due variabili intere. Si dica quanto valgono
rispettivamente x, y, *P, *Q, *R dopo l’esecuzione della seguente sequenza di istruzioni.
x = 3; y = 5;
P = &x; Q = &y; R = P;
*R = 10; y = x + *Q; x = x + *P;
Q = R; P = Q
Soluzione
Al termine dell’esecuzione della sequenza di istruzioni le variabili valgono:
x = 20, y = 15, P, Q, R puntano tutti a x e quindi *P = *Q = *R = 20.
Esercizio 4
Scrivere un programma C che esegue le seguenti operazioni.
Legge da tastiera una sequenza di esattamente 64 pacchetti di 4 bit ciascuno (si ricorda che un
pacchetto di 4 bit altro non è che una sequenza di 4 interi che possono assumere solo i valori
0 o 1). Un pacchetto è ammissibile solo se contiene solo 0 e 1; pacchetti non ammissibili
vanno reimmessi.
Un pacchetto ammissibile è detto corretto se e solo se il numero di 1 in tutto il pacchetto è
pari.
Il programma, quindi, per ogni pacchetto ammissibile, verifica se il pacchetto è corretto, e,
dopo avere letto tutti i pacchetti, stampa prima i pacchetti corretti, quindi quelli scorretti.
Soluzione
#define MAX_PACC 64
typedef int TipoPacchetto[4];
typedef enum {false, true} bool;
main()
{ TipoPacchetto corretti[MAX_PACC], non_corretti[MAX_PACC],
corrente;
int i, j, k, h, somma, n_corretti, n_non_corretti;
bool ammissibile;
i = 0; j = 0; k = 0;
while(i<MAX_PACC) {
printf(“Pacchetto numero %d (4 bit, separare i singoli bit con
degli spazi): ”, i+1);
scanf(“%d %d %d %d”, &corrente[0], &corrente[1], &corrente[2],
&corrente[3]);
ammissibile = true;
somma = 0;
for(h=0 ; h<4 ; h++) {
if(corrente[h] > 1 || corrente[h] < 0) {
ammissibile = false;
} else {
somma += corrente[h];
}
}
if(ammissibile) {
if (somma % 2 == 0) {
for(h=0 ; h<4 ; h++) { corretti[j][h] = corrente[h];}
j++;
} else {
for(h=0 ; h<4 ; h++) { non_corretti[k][h] = corrente[h];}
k++;
}
i++;
} else {
printf(“Pacchetto immesso non ammissibile, reimmetterlo!\n”);
}
}
n_corretti = j;
n_non_corretti = k;
printf(“Pacchetti corretti:\n”);
for(j=0 ; j<n_corretti ; j++) {
for(h=0 ; h<4 ; h++) {printf(“%d”, corretti[j][h]); }
printf(“\n”);
}
printf(“Pacchetti NON corretti:\n”);
for(j=0 ; j<n_non_corretti ; j++) {
for(h=0 ; h<4 ; h++) {printf(“%d”, non_corretti[j][h]); }
printf(“\n”);
}
}
Esercizio 5
Si abbia un file (binario) FileFatture contenente fatture. Ogni fattura sia del tipo TipoFatture
dichiarato qui sotto.
typedef struct {
unsigned int NumFattura;
char Nome[30];
char Cognome[40];
float Importo;
char PartitaIva [12];
…/*altri campi irrilevanti per l’esercizio*/
} TipoFatture;
Si scriva una procedura che aggiorna una (e una sola!) fattura del file cambiandone l’importo
da Lire a Euro (si ricorda che un Euro vale 1936,27 Lire). La procedura riceve come
parametro il numero d’ordine della fattura nel file (si assuma che il numero di fattura –
denotato dal campo NumFattura- sia anche la posizione assunta dalla fattura nel file, cioè che
la fattura numero 1 sia la prima, quella numero 2 la seconda, ecc.).
Prima di procedere alla codifica della procedura si dichiarino eventuali variabili globali da
essa utilizzate.
Si supponga che il file sia già aperto al momento della chiamata della procedura.
Soluzione
FILE *file_fatture;
void aggiorna(unsigned int num_ord) {
TipoFatture fattura;
long pos_corr;
pos_corr = ftell(file_fatture);
fseek(file_fatture, sizeof(TipoFatture)*(num_ord-1), SEEK_SET);
fread(&fattura, sizeof(TipoFattura), 1, file_fatture);
fattura.Importo = fattura.Importo/1936.27;
fseek(file_fatture, sizeof(TipoFatture)*(num_ord-1), SEEK_SET);
fwrite(&fattura, sizeof(TipoFattura), 1, file_fatture);
fseek(file_fatture, pos_corr, SEEK_SET);
/*anche se non esplicitamente richiesto, la procedura lascia inalterata
la posizione corrente del file*/
}
Esercizio 6
Si definisca un tipo di dato Giocattolo costituito dal nome del giocattolo (ad esempio
“Trenino_elettrico”), dalla data di fabbricazione, e dal prezzo. Se necessario, si definiscano in
precedenza ulteriori tipi di dato utili per la definizione del tipo Giocattolo.
Si definisca poi un nuovo tipo Bambino, costituito dal nome del bambino e da una sequenza
GiocattoliPosseduti. Tale sequenza è costituita a sua volta da un array di 10 elementi, ognuno
dei quali essendo un puntatore al tipo Giocattolo.
Si dichiarino successivamente due variabili, Giocattoli e Bambini, consistenti in due array,
rispettivamante di MaxGiocattoli elementi del tipo Giocattolo e MaxBambini elementi del
tipo Bambino. MaxGiocattoli e MaxBambini, pure da definire, sono i due valori costanti 20 e
30.
Si può assumere che nè i nomi dei giocattoli, nè i nomi dei bambini siani più lunghi di 30
caratteri.
Soluzione
#define MaxGiocattoli 20
#define MaxBambini 30
typedef struct {
int giorno;
int mese;
int anno;
} Data;
typedef char string[30];
typedef struct {
string nome;
Data dataFabbricazione;
float prezzo;
} Giocattolo;
typedef struct {
string nome;
Giocattolo *GiocattoliPosseduti[10];
} Bambino;
Giocattolo Giocattoli[MaxGiocattoli];
Bambino Bambini[MaxBambini];
Esercizio 7
Con riferimento all’esercizio 6, si scriva un frammento di programma C che:
Legga da tastiera, mediante opportuno dialogo con l’utente, il nome di un bambino e, se
questo compare nell’elenco dei bambini, stampa l’elenco dei nomi dei giocattoli da lui
posseduti.
Nello scrivere il frammento di programma (ossia una sequenza di istruzioni che non
costituisce necessariamente un programma completo) si assuma che l’elenco dei bambini e
l’elenco dei giocattoli siano costituiti dalle variabili Bambini e Giocattoli già in memoria.
Per semplicità si può assumere che l’utente non commetta errori durante il dialogo con la
macchina (ad esempio non fornisca nomi troppo lunghi).
Si facciano inoltre le seguenti assunzioni:
•
Ogni stringa di caratteri che costituisca un nome (di giocattolo o di bambino) sia
terminata dal carattere “A capo” (‘\r’)
•
Se il bambino possiede solo k giocattoli, k < 10, gli ultimi 10 – k puntatori valgono
NULL.
•
La variabile NumBambini, che pure si assume sia già in memoria, contiene il numero
di bambini effettivamente presenti nell’elenco dei bambini.
Un esempio di dialogo utente-programma è il seguente (NB: dopo aver battuto i caratteri
che compongono il nome del bambino l’utente batte il tasto “A capo”)
-------------------------------------------------------------------------Immetti il nome di un bambino:
Giovanni
I giocattoli posseduti da Giovanni sono:
Trenino_elettrico
Cavallo_a_dondolo
-------------------------------------------------------------------Soluzione
#include <stdio.h>
#define ….
typedef ….
main ()
{
Giocattolo Giocattoli[MaxGiocattoli];
Bambino Bambini[MaxBambini];
string NomeBambino;
boolean trovato;
int i, k, j, LunghNomeBamb, NumBambini;
/* NumBambini indica il numero di bambini presenti nell’elenco*/
...
/* parte di programma omessa. Comprenderà, tra l’altro,
* il dialogo utente-macchina per acquisire i dati e memorizzarli
* nelle variabili Giocattoli e Bambini*/
printf (“Immetti il nome del bambino di cui vuoi conoscere i
giocattoli:\n”);
i = 0;
scanf("%c", & NomeBambino[i]);
while (NomeBambino[i] != '\r') {
i++;
scanf("%c", &NomeBambino[i])
}
LunghNomeBamb = i;
/*Si cerca nell’array Bambini il nome immesso*/
trovato = false;
k = 0;
while (! trovato && k < NumBambini) {
for(i = 0; i <= LunghNomeBamb &&
Bambini[k].nome[i] == NomeBambino[i]; i++){};
/*Si incrementa i finché la condizione rimane vera*/
if (i > LunghNomeBamb){
trovato = true;
} else {
k++;
}
}
if (! trovato){
printf (“Il bambino indicato non compare nell’elenco\n”);
} else {
printf (“I giocattoli posseduti dal bamino sono:\n”);
i = 0;
while (i<10 && Bambini[k].GiocattoliPosseduti[i] != NULL) {
for (j = 0; j < 30 &&
Bambini[k].GiocattoliPosseduti[i]->nome[j] != ‘\r’;
j++){
printf (“%c”, Bambini[k].GiocattoliPosseduti [i] -> nome[j]);
}
i++;
printf (“\n”),
}
}
/*fine del frammento di programma*/
...
}
Esercizio 8
Scrivere un programma che legge da tastiera due sequenze di caratteri alfabetici minuscoli
(non sono ammessi numeri, segni di punteggiatura, ecc.) separate dal carattere di spazio ed
anche terminate dal carattere di spazio, e dice all'utente se le due parole sono una l'anagramma
dell'altro. Nella sequenza sono ammesse ripetizioni della stessa lettera. Si trascuri il fatto che
le parole possano avere un significato in italiano oppure no.
Si supponga pure che l'utente non inserisca mai parole più lunghe di 50 caratteri. Se l'utente
inserisce simboli non ammessi, questi vanno ignorati.
Esempio di funzionamento:
Inserisci le parole (separate e terminate da uno spazio):
terkmit<spazio>mertkit<spazio>
Le due parole sono una l'anagramma dell'altra.
Soluzione
main ()
{
char prima_parola[50], seconda_parola[50];
char curr;
int l1 = 0, l2 = 0, i, j;
int sono_anagrammi, trovato;
printf("Inserisci le parole (separate e terminate da uno spazio)\n");
do {
scanf("%c", &curr);
if (curr >= 'a' && curr <= 'z') {
prima_parola[l1] = curr; l1++;
}
} while(l1<50 && curr != ' ');
do {
scanf("%c", &curr);
if (curr >= 'a' && curr <= 'z') {
seconda_parola[l2] = curr; l2++;
}
} while(l2<50 && curr != ' ');
sono_anagrammi = 1; i = 0;
while(sono_anagrammi && i<l1){
trovato = 0; j = 0;
while(!trovato && i<l2){
if(prima_parola[l1] == seconda_parola[l2]){
trovato = 1;
seconda_parola[l2] = '#';
}
j++;
if (!trovato) sono_anagrammi = 0;
}
i++;
}
if(sono_anagrammi == 1)
printf("Le due parole sono una l'anagramma dell'altra.\n");
else
printf("Le due parole NON sono una l'anagramma dell'altra.\n");
}
Esercizo 9
Si definisca(no) i(l) tipi(o) di dato che serve(ono) per contenere le informazioni relative al
listino prezzi di un concessionario di motocicli che fa anche officina meccanica. Per ogni
modello di motociclo venduto devono essere definiti:
nome del modello (massimo 30 caratteri), marca (massimo 20 caratteri), codice identificativo
(10 cifre), prezzo, cilindrata (in cc), elenco dei pezzi sostituibili del motociclo. Di ogni pezzo
sostituibile devono essere definiti: descrizione del pezzo (massimo 100 caratteri), codice
identificativo (10 cifre), prezzo, numero di giorni in cui il pezzo arriva se ordinato, ore di
lavoro necessarie per la sostituzione.
Si supponga pur che il numero delle parti sostituibili di un motociclo sia al massimo 50.
Soluzione
typedef char TipoCodice[10];
typedef struct {
char descrizione[100];
TipoCodice codice;
unsigned int prezzo;
unsigned int ritardo_ordine;
unsigned int ore_lavoro;
} TipoPezzo;
typedef struct {
char nome[30];
char marca[20];
TipoCodice codice;
unsigned int prezzo;
unsigned int cilindrata;
TipoPezzo pezzi_sost[50];
unsigned int n_pezzi_sost;
} TipoMotociclo;
Esercizio 10
Con riferimento all'esercizio 9 si scriva un sottoprogramma che prende in ingresso la
descrizione di un motociclo ed un elenco di codici di pezzi da sostituire, e ritorna:
•
il costo totale della sostituzione, sapendo che ogni ora di lavoro costa 20 euro;
•
il numero di giorni che bisogna aspettare per avere la riparazione efettuata nell'ipotesi
che tutti i pezzi siano da ordinare, e che la riparazione possa essere fatta in giornata
una volta che tutti i pezzi arrivano;
•
un codice che è 0 se il calcolo fallisce (per esempio se uno dei codici di pezzo da
sostituire non è in realtà un pezzo del motociclo), 1 altrimenti.
Qualunque sottoprogramma ausiliaro (che non faccia parte della libreria standard del C) che
viene eventualmente usato nel sottoprogramma precedente deve essere definito nella sua
interezza.
Soluzione
int calcolaCosto (TipoMotociclo moto, TipoCodice pezzi[],
unsigned int npezzi, unsigned int *costo,
unsigned int *giorni){
TipoPezzo pezzo;
int i;
unsigned int c_parz = 0, g_parz = 0;
for (i = 0; i<npezzi ; i++){
if(trovaPezzo(moto.pezzi_sost, moto.npezzi,
pezzi[i], &pezzo) == 0){
return 0;
}
c_parz += pezzo.prezzo;
if (pezzo.ritardo_ordine > g_parz){
g_parz = pezzo.ritardo_ordine;
}
}
*costo = c_parz;
*giorni = g_parz + 1; /* contiamo anche il giorno per
la riparazione */
return 1;
}
/* La seguente funzione prende in ingresso un elenco di pezzi
* ed un codice di pezzo e ritorna il tipo di pezzo presente
* nella lista (se presente).
* Se il codice non e' presente nella lista ritorna 0, altrimenti 1.
*/
int trovaPezzo( TipoPezzo pezzi[], unsigned int npezzi,
TipoCodice cod, TipoPezzo *pezzo){
int i;
if (pezzi == NULL) return 0;
for (i = 0 ; i<npezzi; i++){
if (strcmp(pezzi[i].codice, cod) == 0) {
*pezzo = pezzi[i];
return 1;
}
}
return 0;
}
Esercizio 11
Definire un tipo di dato TipoStrumentista che descrive i dati relativi ad un musicista
jazz. Ogni musicista è definito da un nome (massimo 40 caratteri), da una data di nascita, e
dallo strumento che suona. Ogni musicista suona un solo strumento, ed il tipo di strumento
suonato può essere solo uno dei seguenti (non sono ammessi altri strumenti): pianoforte,
basso, batteria, sax, tromba, trombone, flauto, clarinetto, voce.
Definire un tipo TipoQuartetto che contiene i dati relativi ad un quartetto di musicisti.
Ogni quartetto è caratterizzato da un nome (al massimo 30 caratteri) e da esattamente 4
musicisti (non uno di più, non uno di meno).
Definire infine una variabile ElencoQuartetti che può contenere al massimo 100
quartetti.
(se si ritiene utile, si possono definire altri tipi di dati, di supporto a quelli richiesti)
Soluzione
#define L_NOME_MUS 40
#define L_NOME_QUAR 30
#define MAX_QUARTETTI 100
typedef struct {
short giorno;
short mese;
int anno;
} TipoData;
typedef enum {pianoforte, basso, batteria, sax, trombone, flauto,
clarinetto, voce} TipoStrumento;
typedef struct {
char nome[L_NOME_MUS+1];
TipoData data_nascita;
TipoStrumento strumento;
} TipoStrumentista;
typedef struct {
char nome[L_NOME_QUAR+1];
TipoStrumentista musicisti[4];
} TipoQuartetto;
TipoQuartetto ElencoQuartetti[MAX_QUARTETTI];
Esercizio 12
Scrivere un frammento di programma C che, per ogni quartetto senza pianoforte (cioè in cui
nessuno strumentista suona il pianoforte) presente nell'elenco ElencoQuartetti, stampa
a video il nome del quartetto. In seguito stampa a video il nome di tutti i quartetti con
pianoforte.
Nel realizzare il frammento di programma si supponga che la variabile ElencoQuartetti
di cui al punto precedente sia già stata inizializzata (sia cioè già stata caricata di dati, che non
devono essere riletti da tastiera), e si supponga inoltre che un'altra variabile numQuartetti,
di tipo int (anch'essa già inizializzata) contenga il numero di quartetti effettivamente inseriti
in ElencoQuartetti.
Soluzione
main()
{
TipoQuartetto ElencoQuartetti[MAX_QUARTETTI];
int numQuartetti[MAX_QUARTETTI];
/* inizializzazione delle variabili sopra dichiarate,
* da considerare già fatta */
TipoQuartetto QuartettiSenzaPiano[MAX_QUARTETTI];
TipoQuartetto QuartettiConPiano[MAX_QUARTETTI];
int numQuarSenzaPiano = 0, numQuarConPiano = 0, i, j, trovato;
for (i=0; i<numQuartetti; i++){
j = 0;
trovato = 0;
while (trovato == 0 && j<4){
if (ElencoQuartetti[i].musicisti[j].strumento == pianoforte){
trovato = 1;
}
j++;
}
if (trovato == 0) {
QuartettiSenzaPiano[numQuarSenzaPiano] = ElencoQuartetti[i];
numQuarSenzaPiano++;
} else {
QuartettiConPiano[numQuarConPiano] = ElencoQuartetti[i];
numQuarConPiano++;
}
}
printf(“Quartetti senza piano:\n”);
for (i=0; i<numQuarSenzaPiano; i++){
printf(“%s\n”, QuartettiSenzaPiano[i].nome);
}
printf(“Quartetti con piano:\n”);
for (i=0; i<numQuarConPiano; i++){
printf(“%s\n”, QuartettiConPiano[i].nome);
}
Esercizio 13
Si definiscano i tipi TipoStrumentista e TipoQuartetto come nell'esercizio 11.
Si definisca inoltre un tipo TipoConcerto costituito dal nome della località in cui il
concerto si è tenuto (massimo 40 caratteri), dalla data in cui si è tenuto il concerto, e dal
quartetto che ha tenuto il concerto.
Soluzione
#define L_NOME_MUS 40
#define L_NOME_QUAR 30
#define MAX_QUARTETTI 100
typedef struct {
short giorno;
short mese;
int anno;
} TipoData;
typedef enum {pianoforte, basso, batteria, sax, trombone, flauto,
clarinetto, voce} TipoStrumento;
typedef struct {
char nome[L_NOME_MUS+1];
TipoData data_nascita;
TipoStrumento strumento;
} TipoStrumentista;
typedef struct {
char nome[L_NOME_QUAR+1];
TipoStrumentista musicisti[4];
} TipoQuartetto;
#define L_NOME_CONC 40
typedef struct {
char nome_loc[L_NOME_CONC+1];
TipoData data;
TipoQuartetto quartetto;
} TipoConcerto;
Esercizio 14
Si supponga di avere un file binario contenente un elenco di concerti. Si supponga inoltre che
il file sia già stato aperto in modalità (binaria) lettura/scrittura.
Si risolva uno (ed uno solo) dei seguenti punti.
Variante a
Dopo avere dichiarato eventuali variabili globali, definire una funzione
CancellaConcertiDiQuartetto che riceve in ingresso il nome di un quartetto, e crea
un nuovo file (sempre binario), di nome NuovaListaConcerti.dat, contenente l'elenco
di tutti i concerti esclusi quelli del quartetto il cui nome è stato passato alla funzione. La
funzione ritorna 1 se l'operazione è andata a buon fine, 0 altrimenti. Il file originario con
l'elenco dei concerti rimane immutato.
Variante b
Dopo avere dichiarato eventuali variabili globali, definire una funzione
CancellaConcertiDiQuartetto che riceve in ingresso il nome di un quartetto, e
cancella dal file con l'elenco dei concerti tutti i concerti tenuti dal quartetto il cui come è stato
passato alla funzione. La funzione ritorna 1 se l'operazione è andata a buon fine, 0 altrimenti;
essa modifica il file originario con l'elenco dei concerti.
In questa variante è ammesso (anzi, è consigliato) aprire file temporanei, in aggiunta al file
originario.
Variante c
Dopo avere dichiarato eventuali variabili globali, definire una funzione
CancellaConcertiDiQuartetto che riceve in ingresso il nome di un quartetto, e
cancella dal file con l'elenco dei concerti tutti i concerti tenuti dal quartetto il cui come è stato
passato alla funzione. La funzione ritorna 1 se l'operazione è andata a buon fine, 0 altrimenti;
essa modifica il file originario con l'elenco dei concerti.
In questa variante non è ammesso aprire file temporanei aggiuntivi, si può lavorare solo sul
file originario.
Aiuto per le varianti b e c: per troncare un file f alla lunghezza data dalla posizione corrente
nel file, l’istruzione da usare è la seguente:
ftruncate(fileno(f), ftell(f));
Soluzione variante a
#include <string.h>
#include <stdio.h>
FILE *f_concerti;
int CancellaConcertiDiQuartetto(char nome_quar[]){
TipoConcerto curr_conc;
FILE *nf = fopen(“NuovaListaConcerti.dat”, “wb”);
if (nf == NULL) return 0;
rewind(f_concerti);
while (!feof(f_concerti)){
if (fread(&curr_conc, sizeof(TipoConcerto), 1, f_concerti) == 1){
if (strcmp(curr_conc.quartetto.nome, nome_quar) != 0) {
if (fwrite(&curr_conc, sizeof(TipoConcerto), 1, nf) != 1){
fclose(nf); return 0;
}
}
} else { fclose(nf); return 0; }
}
if (fclose(nf) == 0) return 1;
else return 0;
}
Soluzione variante b
#include <string.h>
#include <stdio.h>
FILE *f_concerti;
int CancellaConcertiDiQuartetto(char nome_quar[]){
TipoConcerto curr_conc;
FILE *tmp_f = fopen(“_temp.dat”, “wb+”);
if (tmp_f == NULL) return 0;
rewind(f_concerti);
while (!feof(f_concerti)){
if (fread(&curr_conc, sizeof(TipoConcerto), 1, f_concerti) == 1){
if (strcmp(curr_conc.quartetto.nome, nome_quar) != 0) {
if (fwrite(&curr_conc, sizeof(TipoConcerto), 1, tmp_f) != 1){
fclose(tmp_f); return 0;
}
}
} else { fclose(tmp_f); return 0; }
}
rewind(f_concerti);
rewind(tmp_f);
while (!feof(tmp_f)){
if (fread(&curr_conc, sizeof(TipoConcerto), 1, tmp_f) == 1) {
if (fwrite(&curr_conc, sizeof(TipoConcerto), 1, f_concerti) != 1) {
fclose(tmp_f); return 0; }
} else { fclose(tmp_f); return 0; }
}
/* tronco il file all’ultima posizione in cui ho scritto
* (il file riscritto è in generale più corto
* del file originario) */
ftruncate(fileno(f_concerti), ftell(f_concerti));
if (fclose(tmp_f) == 0) return 1;
else return 0;
}
Soluzione variante c
#include <string.h>
#include <stdio.h>
FILE *f_concerti;
int CancellaConcertiDiQuartetto(char nome_quar[]){
TipoConcerto curr_conc;
/* tengo due indici nel file: la prossima posizione in cui devo
* scrivere (pos_next_write) e la prossima posizione da cui devo
* leggere (pos_next_read) */
long pos_next_write, pos_next_read;
rewind(f_concerti);
pos_next_write = ftell(f_concerti);
while (!feof(f_concerti)){
if (fread(&curr_conc, sizeof(TipoConcerto), 1, f_concerti) == 1) {
if (strcmp(curr_conc.quartetto.nome, nome_quar) != 0) {
/* se il concerto è da mantenere, lo riscrivo nel file
* f_concerti alla prossima posizione in cui devo scrivere.
* Prima di scrivere, però, devo memorizzare la poszione
* corrente nel file, perchè a questa posizione dovrò poi
* tornare per ricominciare a leggere. */
pos_next_read = ftell(f_concerti);
/*
*
if
if
mi sposto nel file alla posizione in cui devo scrivere,
e poi effettivamente scrivo. */
(fseek(f_concerti, pos_next_write, SEEK_SET)) return 0;
(fwrite(&curr_conc, sizeof(TipoConcerto), 1, f_concerti) != 1)
return 0;
/* memorizzo la posizione corrente, che è la prossima posizione
* in cui dovrò scrivere, e mi riporto nella posizione che è la
* prossima da cui devo leggere */
pos_next_write = ftell(f_concerti);
if (fseek(f_concerti, pos_next_read, SEEK_SET)) return 0;
}
} else { return 0; }
}
/* mi riporto sulla posizione che è la prossima in cui scrivere
* (cioè appena dopo l’ultimo concerto che va conservato, e tronco il
* file (il file riscritto è in generale più corto del file originario */
if (fseek(f_concerti, pos_next_write, SEEK_SET)) return 0;
ftruncate(fileno(f_concerti), ftell(f_concerti));
return 1;
}
Esercizio 15
Si definisca un tipo di dato ContoCorrente contenente, tra l’altro, almeno i seguenti
campi:
Numero del CC
Nome dell’intestatario
Importo presente sul CC
Si definisca poi un sottoprogramma che riceva come parametro un numero di CC e un
aggiornamento opportunamente codificato (ad esempio, un numero relativo, oppure un
qualificatore “deposito/prelievo” seguito da un valore assoluto) ed apporti l’aggiornamento
richiesto ad un file, supposto già aperto ed il cui descrittore è contenuto in una variabile
globale, di record di tipo ContoCorrente.
Come può cambiare il sottoprogramma nell’ipotesi che nel file il numero di CC coincida con
la posizione occupata dal record (record relativo al CC # 0 in posizione 0, ecc.)?
Parte facoltativa
Si descriva sinteticamente, senza necessariamente codificare l’intero sottoprogramma, come
si potrebbe modificare il sottoprogramma se i parametri di ingresso fossero numero di conto e
nome dell’intestatario, ma uno dei due potesse mancare. Si considerino sia il caso in cui ogni
persona possa essere intestatario al più di un solo CC sia il caso opposto. Sarebbe un
sottoprogramma siffatto il modo migliore per affrontare il problema nella realtà quando
l’utente si presenta allo sportello fornendo solo uno dei dati suddetti? In caso negativo che
alternativa proporreste?
Soluzione
typedef struct {
int CC;
char intestatario[50];
double importo;
} ContoCorrente;
typedef enum {fale, true} boolean;
boolean aggiorna(int n_CC, double variazione){
ContoCorrente curr;
while(fread(&curr, sizeof(ContoCorrente), 1, file) == 1){
if (curr.CC == n_CC){
curr.importo += variazione;
fseek(file, -sizeof(ContoCorrente), SEEK_CUR);
if(fwrite(&curr, sizeof(ContoCorrente), 1, file) == 1){
return true;
} else {
return false;
}
}
}
return false;
}
Se il numero di conto corrente coincide con la posizione nel file, il programma va modificato
come segue:
boolean aggiorna(int n_CC, double variazione){
ContoCorrente curr;
if(fseek(file, sizeof(ContoCorrente)*n_CC, SEEK_SET) != 0){
return false;
}
if (fread(&curr, sizeof(ContoCorrente), 1, file) != 1)
return false;
curr.importo += variazione;
fseek(file, -sizeof(ContoCorrente), SEEK_CUR);
if(fwrite(&curr, sizeof(ContoCorrente), 1, file) == 1){
return true;
} else {
return false;
}
}
Soluzione Parte facoltativa
L’intestazione del sottoprogramma andrebbe modificata come segue:
boolean aggiorna(int *n_CC, char intestatario[], double variazione)
Il numero di conto corrente viene passato come puntatore adesso, per dare la possibilità di
mettere NULL nel caso in cui non si voglia specificare alcun numero di conto corrente.
Nel caso in cui sia il numero di conto che il nome del correntista vengono passati al
sottoprogramma, nel ciclo while che va a trovare i dati del conto corrente da modificare
occorre verificare se entrambi coincidono con i dati del conto appena letto. In caso positivo, si
effettua la modifica, altrimenti, se non è possibile che una persona abbia intestati più conti
correnti, viene segnalato un errore. Se invece una persona può avere intestati più conti
correnti, si continua nella ricerca.
Se invece uno solo tra numero di conto e nome dell’interstatario è specificato, la verifica
viene fatta con quello che c’è e basta (e non è possibile fare la contro-verifica che i dati siano
consistenti tra di loro). Se però è possibile che un correntista abbia più conti correnti e viene
passato solo il nome dell’intestatario, occorre verificare se esistono più CC con lo stesso
intestatario e, in tal caso, sollevare un errore; altrimenti si può procedere con l’aggiornamento.
Un sottoprogramma siffatto non sarebbe la soluzione migliore. La soluzione migliore sarebbe
di avere tre sottoprogrammi separati, uno che prende in ingresso solo il numero di conto
corrente, uno che accetta solo il nome dell’intestatario, ed uno che li accetta entrambi. Il main,
o un sottoprogramma opportuno eventualmente interattivo, dovrebbe decidere quale dei
sottoprogrammi è appropriato.
Esercizio 16
Si consideri un programma contenente, tra l’altro, la seguente dichiarazione
int x
si consideri poi la seguente sequenza di istruzioni appartenente al programma:
P1 = &x;
P = &P1;
*P1 = 10;
**P = *P1 + 2*x;
printf (…, **P);
Parte 1
Si completi la parte dichiarativa del programma con le dichiarazioni necessarie a far sì che il
programma venga compilato con successo –senza segnalazioni di errore e neanche
“warnings” ed eseguito. Si completi inoltre l’istruzione printf con la parte mancante indicata
dai puntini, in modo che essa provochi la stampa del valore indicato da **P.
Parte 2
Assumendo che prima dell’esecuzione della sequenza di istruzioni x contenga il valore 5, si
dica quale valore viene stampato dalla istruzione finale printf.
Soluzione parte 1
int
int
*P1;
**P;
printf (“Il contenuto della cella puntata dalla cella puntata dal
puntatore P è %d \n”, **P)
Soluzione parte 2
Dopo i primi due assegnamenti P1 punta a x e P punta a sua volta a P1. Il terzo assegnamento
deposita perciò il valore 10 in x. Il quarto fa riferimento ancora ad x sia attraverso il doppio
puntamento **P che attraverso il puntamento semplice P1. Perciò il valore 10 + 2*10 = 30
viene depositato in x e successivamente stampato.
Esercizio 17
Si scriva un programma C che esegue le seguenti operazioni. Legge da tastiera una sequenza
di caratteri lunga al massimo 12 caratteri e terminata da '*' e determina se:
1. la sequenza corrisponde ad un numero di telefono (cioè se è composta solo da numeri,
non da altri caratteri)
2. il numero corrisponde ad un cellulare o ad un telefono fisso (un numero di telefono
fisso inizia sempre per '0', tutti gli altri si possono considerare numeri di cellulare).
Esempio di funzionamento del programma:
Inserisci numero: 02 2399 3561
Il numero immesso corrisponde ad un telefono fisso.
Soluzione
#include <stidio.h>
#define MAX_C 12
main()
{
char n_tel[MAX_C];
char curr;
int i, n_c, flag;
/* flag e' uguale a 1 se la sequenza di caratteri contiene
* solo cifre, 0 altrimenti */
flag = 1;
printf("Inserisci numero: ");
n_c = 0;
do {
scanf("%c", &curr);
if (curr != '*') {
n_tel[n_c] = curr;
n_c++;
if (curr < '0' || curr > '9') {
flag = 0;
}
}
} while(n_c < MAX_C && curr != '*');
if (flag == 0 || n_c == 0) {
printf ("la sequenza inserita NON corrisponde ad un numero di
telefono\n");
} else {
if (n_tel[0] == '0') {
printf("Il numero immesso corrisponde ad un telefono fisso\n");
} else {
printf("Il numero immesso corrisponde ad un telefono cellulare\n");
}
}
}
Esercizio 18
Siano date le variabili x1, x2, y1, y2, rispettivamente di tipo <tipo_x1>, <tipo_x2>,
<tipo_y1>, <tipo_y2> ed i sottoprogrammi P1 e P2:
int P1(int **p1, int *p2, int p3){
x1 = x1 + **p1 + *p2 + p3;
return **p1 + *p2 + p3;
}
int P2(int **p1, int *p2, int p3){
x2 = x2 + **p1 + *p2 + p3;
p2 = &p3;
return **p1 + *p2 + p3;
}
Sia dato il corrispondente main:
int main(){
x1 = 1; y1 = &x1;
x2 = 1; y2 = &x2;
x1 = P1(&y1, y1, x1);
x2 = P2(&y2, y2, x2);
printf("Valore di x1: %<codice_x1>; \n Valore di x2: %<codice_x2>");
}
a. Si completi il programma costituito dai sottoprogrammi P1, P2 e main con adeguate parti
dichiarative e direttive in modo che il programma possa essere compilato ed eseguito
correttamente.
b. Si dica poi, spiegandone il perchè, quali sono i valori stampati dalla printf finale del main.
Soluzione punto a.
/* variabili globali */
int x1;
int x2;
int main(){
int *y1;
int *y2;
/* ... */
printf("Valore di x1: %d; \n Valore di x2: %d");
}
Soluzione punto b.
Il valore di x1 è 9, quello di x2 6. Infatti, quando viene invocato P1 la situazione è la
seguente:
x1
1
y1
p1
p2
p3
1
Siccome P1 non cambia la struttura dei puntatori, in P1 prima viene assegnato a x1 il valore
1+1+1+1=4, poi viene ritornato il valore 4+4+1 = 9.
Quando P2 viene invocato, invece, la situazione è la seguente:
x2
1
y2
p1
p2
p3
1
P2 però cambia la struttura dei puntatori dopo che a x2 è assegnato il valore 1+1+1+1=4, e la
modifica come segue:
x2
4
y2
p1
p2
p3
1
Quindi P2 ritorna il valore 4+1+1=6.
Esercizio 19
Si definisca un tipo di dato ContoCorrente contenente, tra l’altro, almeno i seguenti
campi:
Numero del CC
Nome dell’intestatario
Importo presente sul CC
Si definisca anche un tipo di dato AggiornamentoCC che descrive le operazioni di
deposito/prelievo che possono venire effettuate su un conto corrente. AggiornamentoCC
deve contenere le informazioni riguardo a quale conto corrente viene aggiornato, e al tipo di
aggiornamento viene effettuato (deposito/prelievo e la somma depositata/prelevata).
Si definisca poi un sottoprogramma che riceve come parametri i descrittori di due file, uno
contenente dei record di tipo ContoCorrente ed uno contenente dei record di tipo
AggiornamentoCC. Sapendo che in entrambi i file i record sono ordinati in modo
crescente secondo il numero di conto corrente, il sottoprogramma legge gli aggiornamenti dal
file apposito, e li applica ai conti correnti i cui dati sono memorizzati nell'altro file.
Si supponga che:
•
nel file con gli aggiornamenti non ci possano essere due aggiornamenti riguardanti lo
stesso conto corrente;
•
non necessariamente ci sia un aggiornamento per ogni conto corrente;
•
ci possano essere aggiornamenti relativi a conti correnti inesistenti.
Soluzione
typedef struct {
int CC;
char intestatario[50];
double importo;
} ContoCorrente;
typedef struct {
int CC;
double importoAgg;
} AggiornamentoCC;
typedef enum {false, true} bool;
bool aggiornaDaFile(FILE *conti, FILE *agg){
ContoCorrente conto_corr;
AggiornamentoCC agg_corr;
bool stop = false;
rewind(conti);
rewind(agg);
if (feof(conti) || feof(agg)) return true;
if (fread(&conto_corr, sizeof(ContoCorrente), 1, conti) != 1) return
false;
if (fread(&agg_corr, sizeof(AggiornamentoCC), 1, agg) != 1) return false;
while(!stop){
if (agg_corr.CC == conto_corr.CC){
conto_corr.importo += agg_corr.importo;
fseek(conti, -sizeof(ContoCorrente), SEEK_CUR);
if(fwrite(&curr, sizeof(ContoCorrente), 1, file) != 1) return false;
if (feof(conti) || feof(agg)) {
stop = true;
} else {
if (fread(&conto_corr, sizeof(ContoCorrente), 1, conti) != 1)
return false;
if (fread(&agg_corr, sizeof(AggiornamentoCC), 1, agg) != 1)
return false;
}
} else if(agg_corr.CC < conto_corr.CC) {
if (feof(agg)) {
stop = true;
} else {
if (fread(&agg_corr, sizeof(AggiornamentoCC), 1, agg) != 1)
return false;
}
} else {
if (feof(conti)) {
stop = true;
} else {
if (fread(&conto_corr, sizeof(ContoCorrente), 1, conti) != 1)
return false;
}
}
}
return true;
}
Esercizio 20
Scrivere un programma che legge da tastiera una sequenza di esattamente 10 numeri razionali,
ognuno formato da numeratore e denominatore (sia numeratore che denominatore devono
essere numeri interi) e:
a) verifica che tutti abbiano denominatore diverso da zero;
b) se tutti i numeri hanno denominatore diverso da zero stampa a video:
a. la media dei numeri che sono interi (cioè con numeratore multiplo del
denominatore)
b. il prodotto di tutti i numeri
Soluzione
typedef struct {
int num;
int den;
} TipoRazionale;
typedef enum{false, true} bool;
main()
{
TipoRazionale seq[10];
int i,
int n_int = 0;
double media = 0.0;
TipoRazionale prod;
bool flag = true;
for (i=0; i<10; i++){
printf("inserisci numero razionale nella forma
<numeratore/denominatore>: ");
scanf("%d/%d", &seq[i].num, &seq[i].den);
if (seq[i].den == 0) flag = false;
}
if (flag){
for (i=0; i<10; i++){
if (seq[i].num%seq[i].den == 0){
n_int++;
media += seq[i].num/seq[i].den;
}
prod.num = prod.num * seq[i].num;
prod.den = prod.den * seq[i].den;
}
if (n_int > 0) media = media / n_int;
printf("media numeri interi: %f\n", media);
printf("prodotto numeri: %d/%d\n", prod.num, prod.den);
}
}
Esercizo 21
parte a
Si definisca(no) i(l) tipi(o) di dato che serve(ono) per contenere le informazioni relative alla
carriera dei calciatori militanti in serie A. Per ogni calciatore devono essere definiti:
Nome, Cognome, Data di nascita, Elenco dei dati delle stagioni giocate in Serie A (per ogni
stagione giocata in serie A deve essere definito: anno, squadra in cui si è giocato, numero di
partite giocate, numero di gol segnati), Media dei gol segnati per anno.
Si assuma pure che un giocatore, in una stagione, gioca per al massimo una squadra.
parte b
Si scriva un sottoprogramma che prende in ingresso un file binario (supposto già aperto sia in
letture che in scrittura) contenente i dati di tutti i calciatori di serie A, privi della media dei
gol segnati per anno e lo aggiorna inserendo nell’apposito campo la media suddetta.
Soluzione parte a
typedef struct {
short giorno;
short mese;
unsigned int anno;
} TipoData;
typedef struct {
char nome[30];
char cognome[30];
TipoData data_nascita;
TipoStagione stagioni[30];
int n_stagioni;
float media_gol;
} TipoGiocatore;
typedef struct {
int anno;
char squadra[20];
int n_partite;
int n_gol;
} TipoStagione;
Soluzione parte b
void clacolaMedie(FILE *f){
rewind(f);
TipoGiocatore g;
while(fread(&g, sizeof(TipoGiocatore), 1, f) == 1){
g.media_gol = clacolaMediaGol(g.stagioni, n_stagioni);
fseek(biblio, -(sizeof(TipoGiocatore)), SEEK_CUR);
fwrite(&g, sizeof(TipoGiocaotre), 1, f);
}
}
Laddove la funzione calcolaMediaGol è definita come segue:
float clacolaMediaGol(TipoStagione s[], int num_stag){
int i;
float somma = 0;
for(i =0; i<num_stag; i++) somma += s[i].n_gol;
if(num_stag > 0) return somma/n_stag
else return 0;
}
Esercizio 22
Si definiscano i seguenti tipi di dati.
IstitutoOspedaliero, caratterizzato da un nome e da un indirizzo, e che può essere o
privato o pubblico.
Medico: ogni medico ha un nome e un indirizzo, e può essere o un medico della mutua,
oppure no. Se il medico non è della mutua, questi afferisce ad un istituto ospedaliero (se
invece il medico è della mutua, non afferisce ad alcun ospedale).
Paziente, caratterizzato da un nome e da un codice identificativo alfanumerico di 10
caratteri; ogni paziente ha un medico della mutua, ed ha al massimo 20 ricoveri in ospedale.
Un ricovero in ospedale (descritto dal tipo di dato Ricovero) si caratterizza per una data di
inizio ricovero, una data di fine ricovero, l'istituto ospedaliero in cui il ricovero è stato
effettuato e, eventualmente, l'operazione chirurgica effettuata (l'operazione chiurgica durante
un ricovero è opzionale, ci può essere oppure no).
Un'operazione chirurgica si caratterizza per la data in cui viene effettuata, il medico che la
esegue, ed ha associata una descrizione a parole che dice di che cosa l'operazione è consistita.
Soluzione
typedef enum{false, true} bool;
typedef struct {
char nome[50];
char indirizzo[70];
bool privato;
} IstitutoOspedaliero;
typedef struct {
char nome[30];
char indirizzo[70];
bool dellaMutua;
IstitutoOspedaliero *istituto;
} Medico;
typedef struct {
char nome[30];
char id_sanitario[10];
Medico med;
Ricovero ricoveri[20];
} Paziente;
typedef struct {
TipoData inizio;
TipoData fine;
IstitutoOspedaliero ospedale;
Operazione *op;
} Ricovero;
typedef struct {
TipoData data;
Medico med;
char descr[200];
} Operazione;
Esercizio 23
Sia dato un tipo di file di tipo testo (file di caratteri), contenente un elenco di record relativi a
dei medici, ognuno con i seguenti dati: nome, indirizzo, si/no a seconda che il medico sia
della mutua oppure no. Se il medico non è della mutua, il file contiene anche il nome e
l'indirizzo dell'istituto ospedaliero a cui fa riferimento, ed il fatto che questo sia pubblico o
privato ("si" se è pubblico, "no" se è privato).
Ogni dato (nome indirizzo, ecc.) si trova una riga diversa, e ogni record termina con una riga
contenente un #.
Un esempio di record è il seguente:
Mario Ferrari
Corso Plebisciti, 12, Milano
si
#
Umberto Veronesi
via della Spiga, 4, Milano
no
Istituto Oncologico Europeo
via Ripamonti 435, Milano
no
#
Si scriva una procedura che prende in ingresso il nome di un file del tipo di cui sopra, e crea
un file binario "istitutiOspedalieri" che contiene una serie di elementi di tipo
IstitutoOspedaliero. Gli elementi di tipo IstitutoOspedaliero scritti nel file
"istitutiOspedalieri" sono tutti e soli gli istituti che compaiono nel file di tipo testo il cui nome
è ricevuto in ingresso, scritti in un ordine a discrezione dello studente.
Bonus di 3 punti se il file "istituti ospedalieri" è creato in modo che un istituto ospedaliero
compaia al massimo una volta nel file (cioè se non ci sono ripetizioni di istituti ospedalieri).
Soluzione
void scrivi_ospedali (char file_medici[]){
FILE *f_med, *f_osp;
char temp[100];
char mutua[3];
char privato[3];
IstitutoOspedaliero ist;
f_med = fopen(file_medici, "r");
f_osp = fopen("istitutiOspedalieri", "wb");
while(!feof(f_med)){
/* le righe delle quali non mi interessa il contenuto le memorizzo
* in un array 'temp' grande
* a sufficienza per contenere tutte le stringhe di interesse.
*/
fgets(temp, 30, f_med);
fgets(temp, 70, f_med);
fgets(mutua, 3, f_med);
if(strcmp(mutua, "no") == 0){
fgets(ist.nome, 50, f_med);
fgets(ist.indirizzo, 70, f_med);
fgets(privato, 3, f_med);
if(strcmp(privato, "si") == 0){
ist.privato = true;
} else {
ist.privato = false;
}
/* versione semplice, che non si preoccupa di evitare possibili
* ripetizioni dello stesso istituto ospedaliero nel file di output.
*/
fwrite(&ist, sizeof(IstitutoOspedaliero), 1, f_osp);
}
/* suppongo che il formato del file sia corretto, e non faccio alcuna
* verifica sul fatto che la prossima riga contenga esattamente un '#'
* oppure no. Un'alternativa sarebbe di controllare che la riga inizi
* effettivamente per '#', e ritornare un errore in caso contrario.
*/
fgets(temp, 80, f_med);
}
fclose(f_osp);
fclose(f_med);
}
Se avessi voluto evitare di avere ripetizioni di istituti ospedalieri nel file di output mi sarei
potuto appoggiare sulla seguente procedura ausiliaria istituto_presente, che riceve in
ingresso il descrittore di un file binario (gia' aperto sia in lettura che in scrittuta) contente i
dati di istituti ospedalieri, ed il nome di un istituto ospedaliero, e ritorna true se nel file esiste
un record corrispondente al nome passato. Si noti che, se l'istituto non viene trovato, il cursore
del file si trova in fondo al file stesso, altrimenti si trova sull'elemento appena successivo a
quello con nome uguale a quello passato come parametro.
bool istituto_presente(FILE *file, char nome_osp[]){
IstitutoOspedaliero ist;
rewind(file);
while(!feof(file)){
fread(&ist, sizeof(IstitutoOspedaliero), 1, file);
if(strcmp(ist.nome, nome_osp) == 0) return true;
}
return false;
}
Avendo a disposizione la procedura istituto_presente, al posto della semplice
fwrite, nel corpo della procedura scrivi_ospedali va sostituito il seguente pezzo di
codice:
if(!istituto_presente(f_osp, ist.nome)) {
fwrite(&ist, sizeof(IstitutoOspedaliero), 1, f_osp);
}
Si noti inoltre che il file "istitutiOspedalieri" in questo caso non puo' essere piu' aperto solo in
scrittura, ma anche in lettura, quindi la chiamata alla fopen di "istitutiOspedalieri" va
modificata sostituendo al posto della modalita' di apertura "wb" la modalita' "wb+" come
illustrato di seguito:
f_osp = fopen("istitutiOspedalieri", "wb+");
Esercizio 24
Si considerino le seguenti dichiarazioni:
typedef int
int
x, y;
int
*a;
tipo1
*tipo1;
b;
Si dica, per ognuna delle seguenti sequenze di istruzioni C, se essa è corretta o no; in caso positivo si dica qual è
il risultato prodotto; in caso negativo si dica in che cosa consiste l’errore e se si tratta di errore a compile-time o
a run-time.
Sequenza 1:
x = 0; y = 1; a = NULL; b = x; a = b; printf (“il valore di x e y è, rispettivamente, %d, %d, \n”, x, y);
Sequenza 2:
scanf (“%d”, &y); a = NULL; x = 0;
if (y > 0) {b = a; x = *b + y; }
printf (“il valore di x e y è, rispettivamente, %d, %d, \n”, x, y);
Sequenza 3:
a = &y; x = 2; y = 5; b = a; a = NULL; *b = y + x;
printf (“il valore di x e y è, rispettivamente, %d, %d, \n”, x, y);
Soluzione
Sequenza 1: è scorretta in quanto l'assegnamento b=x non ha senso (b è un puntatore ad
intero, x è un intero. Questo è un errore a compile-time (lo riconosce il compilatore).
Sequenza 2: è scorretta in quanto, se il valore y immesso dall'utente è > 0, prima viene
eseguito l'assegnamento b=a (in cui b va a puntare a NULL, in quanto a era stato inizializzato
a NULL), e poi si cerca di dereferenziare b (*b), che però non è ammissibile in quanto b punta
a NULL. Questo è un errore a run-time (lo si trova solo facendo girare il programma e
fornendo in ingresso un valore di y > 0).
Sequenza 3: è corretta, e stampa 2 per x e 7 per y. Infatti, prima dell'istruzione *b=y+x si ha
una situazione in cui x vale 2, y vale 5, b punta a y, a punta a NULL. Quindi l'assegnamento
mette il valore 7 (5+2) nella variabile puntata da b, che è y.
Esercizio 25
Si scriva un programma che:
•
Legge dallo StandardInput due stringhe di caratteri (lunghe al massimo 100 caratteri l'una) separate tra
loro dal carattere speciale (non appartenente alle stringhe) ‘#’ e terminate dallo stesso carattere '#' (si
supponga pure che l'utente non immetta mai stringhe più lunghe di 100 caratteri).
•
Verifica che le lunghezze delle due stringhe (senza contare il carattere '#') differiscano al massimo di
un’unità. In caso contrario interrompa l’esecuzione scrivendo sullo StandardOutput un opportuno
messaggio.
•
Scriva sullo StandardOutput una stringa ottenuta alternando i caratteri delle due stringhe di ingresso (un
carattere di una stringa seguito da un carattere dell’altra mantenendo l’ordine originario tra i caratteri
della stessa stringa) secondo la regola seguente:
o
Se una delle due stringhe è più lunga dell’altra si deve cominciare con il primo carattere della
stringa più lunga.
o
Se le due stringhe sono di lunghezza uguale, si può cominciare con una qualsiasi delle due.
o
Facoltativamente, se la stringa risultante è più lunga di 80 caratteri, ogni 80 caratteri scritti si
deve andare a capo.
Soluzione
#include <stdio.h>
#define MAX_L 100
main ()
{
char s1[MAX_L], s2[MAX_L], curr;
int n_el1=0, n_el2=0;
int i;
do{
scanf("%c", &curr);
if (curr != '#'){
s1[n_el1] = curr;
n_el1++;
}
} while(curr != '#');
do{
scanf("%c", &curr);
if(curr != '#'){
s1[n_el2] = curr;
n_el2++;
}
} while(curr != '#');
if(n_el1-n_el2 <= 1 && n_el1-n_el2 >= -1){
/* caso in cui la stringa 1 è più lunga della stringa 2 */
if(n_el1 > n_el2){
for (i=0; i<n_el2; i++){
printf("%c%c", s1[i], s2[i]);
if(((i+1)*2) % 80 == 0)
printf("\n");
} /* chiude il for */
printf("%c, s1[n_el1-1])
} else {
/*n_el2 >= n_el1*/
for (i=0; i<n_el1; i++){
printf("%c%c", s2[i], s1[i]);
if(((i+1)*2) % 80 == 0)
printf ("\n");
} /* chiude il for */
/*se le due stringhe sono di lunghezza diversa*/
if(n_el2 > n_el1)
printf ("%c, s2[n_el2-1]);
} /* chiude il ramo else dell’if precedente*/
} else {
printf ("Le lunghezze delle stringhe differiscono tra loro di più di
una unità");
}
}
Esercizio 26
Si scriva un programma che, non facendo uso di accesso diretto a file (ossia usando
esclusivamente le funzioni di libreria fopen, fclose, fread, fwrite e rewind), dato un file di
interi "InputInteri" produca un nuovo file "OutputInteri" contenente gli stessi elementi del file
di ingresso ma scritti in ordine inverso. Si assuma che la memoria centrale non sia
sufficientemente grande da contenere l’intero file ma possa contenerne circa i 2/3.
NB:
1.
Tra le varie possibili soluzioni saranno valutate meglio quelle più efficienti.
2.
E’ auspicata una soluzione che faccia uso di opportuni sottoprogrammi. Alcuni di
essi, eventualmente, potrebbero essere definiti anche solo parzialmente mediante
pseudocodice, evitando una codifica completa.
3.
Eventualmente si può assumere l’ipotesi semplificativa che la dimensione del file
sia nota a priori e valga la costante K. In tal caso il punteggio massimo
dell’esercizio viene diminuito di 1 punto.
Soluzione
main ()
{
/* elInFile calcola il numero di interi nel file binario f
* (supposto gia' aperto in sola lettura). */
long int elInFile(FILE *f);
/* readArrayFromFile prende in ingresso il descrittore di un file binario
* (supposto aperto lettura) ed un array di interi, e legge n_el
* interi dal file, memorizzandoli
* nell'array (supposto grande a sufficienza per contenere i dati).
*/
void readArrayFromFile(FILE *f, int *ar, long int n_el);
/* reverseArrayInFile prende in ingresso il descrittore di un file
* binario (supposto vuoto e aperto in sola scrittura) ed un array di
* interi di lunghezza n_el e scrive il contenuto dell'array nel file,
* partendo dall'ultimo elemento dell'array fino al primo.
*/
void reverseArrayInFile(FILE *f, int *ar, long int n_el);
/* appendFile prende in ingresso i descrittori di due file binari
* fromFile ed inFile, il primo aperto in lettura, il secondo in
* scrittura, e scrive gli elementi del primo file in fondo al secondo,
* mantenendo l'ordine in cui essi compaiono nel primo.
*/
void appendFile(FILE *fromFile, FILE *inFile);
FILE *in, *out, *tempFile;
int *tempAr;
long int tot_n_el, n_el;
in = fopen("InputInteri", "rb");
out = fopen("OutputInteri", "wb");
tot_n_el = elInFile(in);
n_el = tot_n_el/2 + 1;
tempAr = malloc(sizeof(int)*n_el);
rewind(in);
readArrayFromFile(in, tempAr, n_el);
tempFile = fopen("_tf", "wb+");
reverseArrayInFile(tempFile, tempAr, n_el);
n_el = tot_n_el - n_el;
readArrayFromFile(in, tempAr, n_el);
reverseArrayInFile(out, tempAr, n_el);
appendFile(tempFile, out);
fclose(in);
fclose(out);
fclose(temp);
}
long int elInFile(FILE *f){
int temp;
long int res = 0;
rewind(f);
while(fread(&temp, sizeof(int), 1, f) == 1){
res++;
}
return res;
}
void readArrayFromFile(FILE *f, int *ar, long int n_el){
long int i;
for(i=0 ; i<n_el ; i++){
fread(&ar[i], sizeof(int), 1, f);
}
/* oppure, in alternativa, si poteva risolvere tutto con una
* istruzione singola:
* fread(ar, sizeof(int), n_el, f);
*/
}
void reverseArrayInFile(FILE *f, int *ar, long int n_el){
long int i;
for(i=n_el-1 ; i>=0 ; i--){
fwrite(&ar[i], sizeof(int), 1, f);
}
}
void appendFile(FILE *fromFile, FILE *inFile){
int temp;
rewind(fromFile);
while(fread(&temp, sizeof(int), 1, fromFile) == 1){
fwrite(&temp, sizeof(int), 1, inFile);
}
}
Esercizio 27
Parte a.
Definire dei tipi di dato per contenere informazioni relative a patenti e multe.
Una patente è definita da un numero identificativo, dal nome del proprietario, dal suo codice fiscale, da una data
di rilascio e una di scadenza, e da un numero di punti ancora disponibili sulla patente.
Una multa è definita da un numero identificativo, dal numero identificativo della patente cui viene addebitata,
dalla data in cui è stata emessa, dall'ammontare della multa (in euro), dal numero di punti da togliere alla patente
a causa della multa.
Parte b.
Codificare un sottoprogramma che prende in ingresso i descrittori fpat e fmul di 2 file (entrambi supposti
aperti sia in lettura che in scrittura), uno contenente una serie di patenti, ed uno contenente una serie di multe, e
ritorna il descrittore di un nuovo file.
Il sottoprogramma deve realizzare quanto segue: per ogni multa presente nel file fmul, il sottoprogramma
modifica i dati della patente corrispondente nel file fpat, togliendo i punti indicati nella multa.
Se una patente, dopo avere sottratto i punti di una multa, ha un residuo di punti minore o uguale a zero, il
sottoprogramma scrive in un terzo file (il cui descrittore verrà ritornato alla fine) la posizione nel file fpat della
suddetta patente.
Si assuma che nel file fpat le patenti siano elencate in ordine di data di scadenza, mentre nel file fmul le
multe siano ordinate secondo l’identificatore della patente a cui si riferiscono.
Si supponga pure che tutte le multe del file fmul si riferiscano a patenti effettivamente esistenti nel file fpat.
Versione semplificata
Si assuma che per ogni patente nel file fmul si trovi al massimo una multa.
Soluzione parte a
typedef struct {
unsigned long id;
char nome[80];
char CF[16];
TipoData rilascio;
TipoData scadenza;
int punti;
} TipoPatente;
/* dove TipoData è stata più volte dichiarata a lezione e
* esercitazione. */
typedef struct {
unsigned long id;
unsigned long id_pat;
TipoData emessa;
float somma;
int punti;
} TipoMulta;
Soluzione parte b
Versione completa.
FILE *aggiornaPatenti(FILE *fpat, FILE *fmul){
TipoMulta m_cor, m_prec;
unsigned long id_pat;
int totPunti;
long pos_pat;
bool next_pat; /* bool è definito come al solito */
FILE *fsottozero = fopen("invalide.txt", "wb");
rewind(fmul);
while(!feof(fmul)){
next_pat = false;
totPunti = 0;
do {
fread(&m_cor, sizeof(TipoMulta), 1, fmul);
if(totPunti == 0){
/* è la prima multa che leggo relativa alla prossima patente */
totPunti = m_cor.punti;
m_prec = m_cor;
} else if (m_cor.id_pat == m_prec.id_pat){
/* la multa appena letta si riferisce alla stessa patente della
* multa precedente, mi, limito a sommare i punti da togliere */
totPunti += m_cor.punti;
} else {
/* devo passare alla prossima multa; come prima cosa,
* ritorno sulla multa precedente */
fseek(fmul, -(sizeof(TipoMulta)), SEEK_CUR);
m_cor = m_prec;
next_pat = true;
}
} while(!feof(fmul) && next_pat == false);
/* Vado a cercare la patente da modificare nel file di patenti,
* quindi faccio i cambiamenti necessari; */
rewind(fpat);
do {
fread(&p, sizeof(TipoPatente), 1, fpat);
} while(p.id != m_cor.id_pat);
fseek(fpat, -(sizeof(TipoPatente)), SEEK_CUR);
p.punti -= totPunti;
pos_pat = ftell(fpat);
fwrite(&p, sizeof(TipoPatente), 1, fpat);
/* se la patente ha un numero di punti <= 0,
* la segnalo nel file apposito; */
if (p.punti <= 0){
fwrite(&pos_pat, sizeof(long), 1, fsottozero);
}
} /* fine del while esterno */
return fsottozero;
}
Versione semplificata.
FILE *aggiornaPatenti(FILE *fpat, FILE *fmul){
TipoMulta m_cor, m_prec;
unsigned long id_pat;
int totPunti;
long pos_pat;
bool next_pat; /* bool è definito come al solito */
FILE *fsottozero = fopen("invalide.txt", "wb");
rewind(fmul);
while(fread(&m_cor, sizeof(TipoMulta), 1, fmul) == 1){
/* Vado a cercare la patente da modificare nel file di patenti,
* quindi faccio i cambiamenti necessari; */
rewind(fpat);
do {
fread(&p, sizeof(TipoPatente), 1, fpat);
} while(p.id != m_cor.id_pat);
fseek(fpat, -(sizeof(TipoPatente)), SEEK_CUR);
p.punti -= m_cor.punti;
pos_pat = ftell(fpat);
fwrite(&p, sizeof(TipoPatente), 1, fpat);
/* se la patente ha un numero di punti <= 0,
* la segnalo nel file apposito; */
if (p.punti <= 0){
fwrite(&pos_pat, sizeof(long), 1, fsottozero);
}
} /* fine del while esterno */
return fsottozero;
}
Esercizio 28
Parte a.
Definire dei tipi di dato per contenere informazioni relative ad un albero genealogico.
Ogni persona è caratterizzata dai suoi dati anagrafici e dai suoi parenti più stretti.
I dati anagrafici di una persona sono il suo codice fiscale (che è una stringa alfanumerica di
esattamente 16 cifre), nome e cognome, il luogo e la data di nascita, il suo sesso e lo stato
matrimoniale (single o sposato).
Inoltre, ad ogni persona sono associati le seguenti informazioni: il codice fiscale dello
sposo/sposa (naturalmente se la persona è sposata); i codici fiscali dei genitori; il codici fiscali
dei figli (si assuma pure che una coppia non possa avere più di 10 figli). Se qualcuna di queste
informazioni non è disponibile, il cofice fiscale corrispondente contiene solo '0' (per esempio
se la persona non è sposata, il codice fiscale associato allo sposo/a è 0000000000000000).
Parte b.
Codificare un sottoprogramma che prende in ingresso un codice fiscale e le informazioni di
una persona (dati anagrafici e parenti più stretti), e ritorna true se la persona passata ha il
codice fiscale corrispondente al primo parametro.
Parte c.
Codificare un sottoprogramma che prende in ingresso il descrittore di un file binario
(supposto già aperto in sola lettura) contenente le informazioni di un insieme di persone, il
quale stampa a video i nomi delle coppie di persone sposate, indicando prima il marito, e poi
la moglie (deve cioè stampare, su ogni riga, i nomi di una coppia marito-moglie, indicando
prima il marito).
NB: Ogni coppia va stampata una volta sola. L'ordine con cui vengono stampate le coppie
può essere qualunque. Il file in ingresso può anch'esso avere le persone in ordine qualunque.
Il sottoprogramma deve essere side-effect-free, cioè quando termina esso deve lasciare il file
in ingresso ESATTAMENTE nello stesso stato in cui questo era all'inizio del
sottoprogramma.
Eventuali sottoprogrammi di appoggio (che non facciano parte della standard library del C)
devono essere codificati nella loro interezza.
Soluzione parte a
typedef TipoCF char[16];
typedef TipoSesso enum{M, F};
typedef struct {
TipoCF cf;
char nome[30];
char cognome[30];
char luogoNascita[30];
TipoData dataNascita;
TipoSesso s;
bool sposato;
} TipoDatiAnagrafici
typedef struct {
TipoDatiPersona anagrafica;
TipoCF sposo;
TipoCF padre;
TipoCF madre;
TipoCF figli[10];
int nfigli;
} TipoDatiPersona
Con i seguenti classici tipi:
typedef enum{false, true} bool;
typedef struct{
short giorno;
short mese;
int anno;
} TipoData;
Soluzione parte b
bool confrontaCF(TipoCF cf, TipoDatiPersona pers){
int i;
for(i=0; i<16; i++){
if(cf[i] != pers.anagrafica.cf[i])
return false;
}
return true;
}
Soluzione parte c
include #stdio.h;
void stampaSposi(FILE *f;){
bool trovaPersonaInFile(TipoCF cf, FILE *f, TipoDatiPersona
*dpOut);
long oldPos = ftell(f);
TipoCF cfSposo;
TipoDatiPersona dp, sposo;
TipoDatiPersona *marito, *moglie;
rewind(f);
while(!feof(f)){
fread(&dp, sizeof(TipoDati(Persona), 1, f);
if(dp.anagrafica.sposato){
if(trovaPersonaInFile(marito.anagrafica.cf, f, &sposo,)){
if(dp.anagrafica.sesso == M){
marito = &dp;
moglie = &sposo;
} else {
marito = &sposo;
moglie = &dp;
}
printf("%s %s, %s %s\n", marito->anagrafica.nome,
marito->anagrafica.cognome,
moglie->anagrafica.nome,
moglie->anagrafica.cognome);
}
}
}
fseek(f, posCorr, SEEK_SET);
}
/* Funzione che prende in ingresso il codice fiscale di una persona
* ed un file in cui cercarla, e ritorna true se la persona
* esiste nella porzione di file seguente al punto in cui si trova
* il puntatore nel file al momento della chiamata, altrimenti
* ritorna false (nel caso cioè in cui o la persona non esiste,
* oppure, se esiste, si trova nel file in un punto precedente).
* Se la persona esiste, i suoi dati sono caricati nella variabile
* dp passata per indirizzo.
* La funzione lascia il puntatore nel file nel punto in cui lo
* aveva trovato all'inizio dell'esecuzione.
*/
bool trovaPersonaInFile(TipoCF cf, FILE *f, TipoDatiPersona *dpOut){
long posCorr = ftell(f);
TipoDatiPersona dp;
while(!feof(f)){
fread(&dp, sizeof(TipoDati(Persona), 1, f);
if(confrontaCF(cf, dp) == true){
*dpOut = dp;
fseek(f, posCorr, SEEK_SET);
return true;
}
}
fseek(f, posCorr, SEEK_SET);
return false;
}
Esercizio 29
Parte a.
Definire dei tipi di dato per contenere informazioni relative alle misurazioni rilevate dai
sensori del sistema di monitoraggio di un impianto industriale.
Ogni sensore rileva una misurazione che può essere o di temperatura, o di pressione, o di
voltaggio, ed è caratterizzato da un numero identificativo (un intero maggiore o uguale a 1),
da un codice di 3 lettere che ne identifica la posizione, e da un valore reale che indica la
precisione del sensore. Ogni sensore ha un numero identificativo unico (non ci possono essere
2 sensori con lo stesso identificativo), mentre più sensori possono essere messi nella stessa
posizione.
Una misurazione è fatta di: codice identificativo del sensore che ha effettuato la rilevazione;
valore del dato letto, data della rilevazione, ora, minuti e secondi della rilevazione.
Parte b.
Codificare un sottoprogramma che prende in ingresso una misurazione m ed il descrittore f di
un file binario (supposto già aperto sia in lettura che in scrittura) contenente misurazioni
ordinate in ordine di data/ora crescente, ed inserisce m in f, avendo cura di mantenere
l'ordinamento.
NB: Eventuali sottoprogrammi di appoggio (che non facciano parte della standard library del
C) devono essere codificati nella loro interezza.
Parte c.
Codificare un sottoprogramma che prende in ingresso:
il descrittore di un file binario (supposto già aperto in sola lettura) contenente le
informazioni relative ai sensori dell'impianto;
il descrittore di un file binario (supposto già aperto in sola lettura) contenente tutte le
misurazioni effettuate da tutti i sensori dell'impianto, ordinate in ordine di data/ora
crescente;
un codice di 3 lettere indicante una posizione nell'impianto.
Il sottoprogramma stampa a video l'ultimo tra i dati (cioè il dato con data/ora maggiore)
rilevati da sensori che si trovano nella posizione specificata come terzo parametro.
NB: Eventuali sottoprogrammi di appoggio (che non facciano parte della standard library del
C) devono essere codificati nella loro interezza.
Nel file binario con i dati dei sensori, ogni sensore compare una volta sola; i sensori nel file
non sono ordinati secondo nessun ordine particolare.
Soluzione parte a
typedef TipoPos char[3];
typedef TipoSensore enum{T, P, V};
typedef struct {
int id;
TipoSensore tipo;
TipoPos pos;
double prec;
} TipoSensore;
typedef struct {
int idSensore;
double mis;
TipoDataOra dataora;
} TipoMisurazione;
Con i seguenti tipi aggiuntivi:
typedef struct{
short giorno;
short mese;
int anno;
} TipoData;
typedef struct{
short ora;
short minuti;
short secondi;
} TipoOra;
typedef struct{
TipoData d;
TipoOra o;
} TipoDataOra;
Soluzione parte b
include #stdio.h;
void aggiungiMis(FILE *f, TipoMisurazione m){
int dataOraCmp(TipoDataOra d1, TipoDataOra d2);
TipoMisurazione tm;
long pos;
FILE *tmp;
bool added = false;
rewind(f);
while(!feof(f) && !added){
fread(&tm, sizeof(TipoMisurazione), 1, f);
if(dataOraCmp(m.dataora, tm.dataora)<=0){
fseek(f, -sizeof(TipoMisurazione), SEEK_CUR);
pos = ftell(f);
tmp = fopen("_tmp", wb+);
while(!feof(f)){
fread(&tm, sizeof(TipoMisurazione), 1, f);
fwrite(&tm, sizeof(TipoMisurazione), 1, tmp);
}
fseek(f, pos, SEEK_SET);
fwrite(&m, sizeof(TipoMisurazione), 1, f);
while(!feof(tmp)){
fread(&tm, sizeof(TipoMisurazione), 1, tmp);
fwrite(&tm, sizeof(TipoMisurazione), 1, f);
}
added = true;
}
}
if(!added){
fwrite(&m, sizeof(TipoMisurazione), 1, f);
}
}
in cui il tipo bool è definito come al solito e la funzione dataOraCmp ritorna -1, 0, 1 a
seconda che d1 sia <, = o > di d2, ed è definita nel seguente modo:
int dataOraCmp(TipoDataOra d1, TipoDataOra d2){
if (d1.d.anno < d2.d.anno) return -1;
else if (d1.d.anno > d2.d.anno) return 1;
if (d1.d.mese < d2.d.mese) return -1;
else if (d1.d.mese > d2.d.mese) return 1;
if (d1.d.giorno < d2.d.giorno) return -1;
else if (d1.d.giorno > d2.d.giorno) return 1;
if (d1.o.ora < d2.o.ora) return -1;
else if (d1.o.ora > d2.o.ora) return 1;
if (d1.o.minuti < d2.o.minuti) return -1;
else if (d1.o.minuti > d2.o.minuti) return 1;
if (d1.o.secondi < d2.o.secondi) return -1;
else if (d1.o.secondi > d2.o.secondi) return 1;
return 0;
}
Soluzione parte c
include #stdio.h;
void stampaUltimo(FILE *sens, FILE *mis, TipoPos p){
TipoSensore trovaSensoreInFile(int sensID, FILE *f);
long pos;
TipoMisurazione tm;
TipoSensore ts;
fseek(mis, 0, SEEK_END);
pos = ftell(mis);
while(pos>0){
fseek(mis, -sizeof(TipoMisurazione), SEEK_CUR);
fread(&tm, sizeof(TipoMisurazione), 1, mis);
ts = trovaSensoreInFile(tm.idSensore, sens);
if(p[0]==ts.pos[0] && p[1]==ts.pos[1] && p[2]==ts.pos[2]){
printf("%d: %lf (%d/%d/%d %d:%d:%d)\n",
tm.idSensore, tm.mis,
tm.dataora.d.giorno, tm.dataora.d.mese,
tm.dataora.d.anno,
tm.dataora.o.ora, tm.dataora.o.minuti,
tm.dataora.o.secondi);
return;
}
fseek(mis, -sizeof(TipoMisurazione), SEEK_CUR);
pos = ftell(mis);
}
}
/* Funzione che prende in ingresso il codice identificativo di un
* sensore ed un file con dati di sensori, e ritorna la descrizione
* completa del sensore.
* Si suppone che il sensore esista nel file, per cui non viene
* prevista alcuna condizione di errore.
*/
TipoSensore trovaSensoreInFile(int sensID, FILE *f){
TipoSensore ts;
rewind(f);
while(!feof(f)){
fread(&ts, sizeof(TipoSensore), 1, f);
if(ts.id == sensID) return ts;
}
}