Informatica: arte e mestiere
III edizione
Esercizi su Web
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Premessa ....................................................................................................................3
Capitolo 3 Codifica degli algoritmi in un linguaggio di alto livello.........................4
Capitolo 4 Esecuzione di programmi C su macchine reali ........................................8
Capitolo 5 Tipi di dato ..............................................................................................13
Capitolo 6 Strutture di controllo ..............................................................................18
Capitolo 7 Funzioni e procedure..............................................................................27
Capitolo 8 Introduzione alla programmazione ricorsiva .........................................32
Capitolo 9 Gestione dei file .....................................................................................35
Capitolo 10 Strutture dati dinamiche .......................................................................43
Capitolo 14 Archivi e basi di dati ............................................................................57
Capitolo 18 La visione dei sistemi informatici da parte dell’utente finale ..............59
Copyright © 2008 - The McGraw-Hill Companies srl
2
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Premessa
Il presente file contiene numerosi esercizi utilizzabili dai docenti che adottano il testo
“Informatica: arte e mestiere” (II edizione) come materiale didattico ausiliario.
Gli esercizi contenuti nel file non costituiscono un eserciziario; pertanto non possono
e non devono essere utilizzati direttamente dagli studenti dei corsi, ma sono proposti
ai docenti come spunto per completare e verificare l’apprendimento durante lo
svolgimento del corso e in sede d’esame. Di conseguenza, il livello di difficoltà e
complessità è fortemente variabile da esercizio a esercizio; inoltre le soluzioni sono
fornite in forma spesso assai schematica.
Gli esercizi sono suddivisi per capitoli a seconda della pertinenza. Ovviamente, la loro
numerosità e complessità varia anche in funzione del capitolo cui fanno riferimento.
In alcuni casi essi sono del tutto assenti.
È intenzione degli autori aggiornare periodicamente gli esercizi proposti, anche in
funzione di eventuali richieste e suggerimenti, sempre benvenuti.
Copyright © 2008 - The McGraw-Hill Companies srl
3
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Capitolo 3
Codifica degli algoritmi in un linguaggio di alto livello
Il nucleo del linguaggio C: input/output semplificato, variabili, istruzioni condizionali
e cicli, vettori.
Esercizio 3.1
Si descriva un algoritmo, utilizzando il nucleo del linguaggio C descritto nel capitolo
3, che legga dallo standard input due numeri interi positivi e stampi in uscita un
messaggio che indichi se i due numeri sono primi tra loro oppure no.
Soluzione dell’esercizio 3.1
Due numeri m e n sono primi tra loro se e solo se vale che MCD(m, n) = 1. Il
problema si riduce quindi a trovare il massimo comun divisore tra m e n e verificarne
il valore. Utilizziamo l’algoritmo di Euclide descritto nell’Esempio 3.7.
main()
{
/* Si utilizza l’algoritmo di Euclide per calcolare l’MCD */
scanf (m);
scanf (n);
while (m != n)
if (m > n)
m = m - n;
else
n = n - m;
mcd = n;
/* A questo punto si aggiungono le istruzioni che valutano l’MCD */
if (mcd == 1)
printf ("I due numeri sono primi tra loro");
else
printf ("I due numeri non sono primi tra loro");
}
Esercizio 3.2
Si vuole memorizzare in forma compatta un elenco di parole ordinato
alfabeticamente. Allo scopo si osserva che spesso due parole consecutive hanno una
parte iniziale comune. Ogni parola che ha una parte iniziale comune con la precedente
viene quindi rappresentata con una cifra decimale compresa tra ‘2’ e ‘9’ indicante un
numero di lettere uguali a quelle nella parole precedente, seguita dalle altre lettere
della parola. L’assenza di cifra all’inizio della parola ha lo stesso significato della
cifra ‘0’. Ogni parola è separata dalla successiva da uno o più spazi bianchi.
Esempio:
abaco 3te 2bandonare 9to 2normale ammiraglio 6re bitume 3orzolo 8uto
…
Scrivere un programma, utilizzando il nucleo del linguaggio C descritto nel capitolo
3, che esegue lo ‘scompattamento’ di tale rappresentazione, cioè legge dallo standard
input una sequenza di caratteri che rappresenta la codifica abbreviata del testo (si
assuma che la sequenza sia terminata dal carattere speciale ‘#’) e la riscrive nello
Copyright © 2008 - The McGraw-Hill Companies srl
4
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
standard output togliendo le cifre e aggiungendo i caratteri necessari in modo da
rappresentare tutte le parole per esteso.
Esempio, dalla sequenza sopra riportata si ottenga la seguente:
abaco abate abbandonare abbandonato
bitume bitorzolo bitorzoluto …
abnormale
ammiraglio
ammirare
Si scriva poi un programma che esegue l’operazione inversa.
Soluzione dell’esercizio 3.2
main()
{
/* Fase di inserimento del testo compatto */
ContatoreTestoCompatto = 0;
scanf (carattere);
while (carattere != '#')
{
TestoCompatto[ContatoreTestoCompatto] = carattere;
ContatoreTestoCompatto = ContatoreTestoCompatto + 1;
scanf (carattere);
}
LunghTestoCompatto = ContatoreTestoCompatto;
/* Fase di scompattamento del testo */
ContatoreTestoCompatto = 0;
ContatoreTestoNormale = 0;
CaratterePrecedente = ' ';
while (ContatoreTestoCompatto < LunghTestoCompatto)
{
carattere = TestoCompatto[ContatoreTestoCompatto];
/* Se il carattere non è un numero, copialo nel vettore del testo normale */
if (carattere < '0' || carattere> '9')
{
TestoNormale[ContatoreTestoNormale] = carattere;
/* Tiene traccia dell'inizio dell'ultima parola nel testo normale */
if (CaratterePrecedente == ' ' && carattere != ' ')
ContatoreInizioParola = ContatoreTestoNormale;
ContatoreTestoNormale = ContatoreTestoNormale + 1;
}
/* Se è un numero, copia caratteri dall'ultima parola inserita nel testo normale */
else
{
NumLettereUguali = TestoCompatto[ContatoreTestoCompatto] - '0';
for (i = 0; i < NumLettereUguali; i++)
{
TestoNormale[ContatoreTestoNormale + i] =
TestoNormale[ContatoreInizioParola + i];
}
ContatoreInizioParola = ContatoreTestoNormale;
ContatoreTestoNormale = ContatoreTestoNormale + NumLettereUguali;
}
ContatoreTestoCompatto = ContatoreTestoCompatto + 1;
CaratterePrecedente = carattere;
}
/* Fase di stampa del testo scompattato */
for (i = 0; i < ContatoreTestoNormale; i++)
Copyright © 2008 - The McGraw-Hill Companies srl
5
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
printf (TestoNormale[i]);
}
Adesso scriviamo il programma che eseugue l’operazione inversa: genera il testo
‘compattato’ a partire da quello esteso.
main()
{
/* Fase di inserimento del testo normale */
ContatoreTestoNormale = 0;
scanf (carattere);
while (carattere != '#')
{
TestoNormale[ContatoreTestoNormale] = carattere;
ContatoreTestoNormale = ContatoreTestoNormale + 1;
scanf (carattere);
}
LunghTestoNormale = ContatoreTestoNormale;
/* Fase di compattamento del testo */
ContatoreTestoCompatto = 0;
ContatoreTestoNormale = 0;
ContatoreInizioParola = -1;
ContatoreLettere = 0;
ContatoreInizioParolaPrec = 0;
CaratterePrecedente = ' ';
while (ContatoreTestoNormale < LunghTestoNormale)
{
carattere = TestoNormale[ContatoreTestoNormale];
/* Tiene traccia dell'inizio della parola precedente */
/* nel testo normale */
if (CaratterePrecedente == ' ' && carattere != ' ')
{
ContatoreInizioParolaPrec = ContatoreInizioParola;
ContatoreInizioParola = ContatoreTestoNormale;
/* Controlla le lettere della parola corrente */
controlla = 1;
}
/* Se il carattere è presente nella corrispondente posizione */
/* della parola precedente */
if (controlla == 1 &&
carattere == TestoNormale[ContatoreInizioParolaPrec + ContatoreLettere])
{
ContatoreLettere = ContatoreLettere + 1;
ContatoreTestoNormale = ContatoreTestoNormale + 1;
}
/* Se il carattere non è presente nella corrispondente posizione */
/* della parola precedente*/
else
{
/* Non controllare più per la parola corrente*/
controlla = 0;
/* Se vi erano lettere uguali, scrivi il contatore */
if (ContatoreLettere > 0)
{
TestoCompatto[ContatoreTestoCompatto] = ContatoreLettere + '0';
ContatoreLettere = 0;
}
/* Altrimenti, scrivi il carattere */
else
Copyright © 2008 - The McGraw-Hill Companies srl
6
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
{
TestoCompatto[ContatoreTestoCompatto] = carattere;
ContatoreTestoNormale = ContatoreTestoNormale + 1;
}
ContatoreTestoCompatto = ContatoreTestoCompatto + 1;
}
CaratterePrecedente = carattere;
}
/* Fase di stampa del testo compattato */
for (i = 0; i < ContatoreTestoCompatto; i++)
printf (TestoCompatto[i]);
}
Copyright © 2008 - The McGraw-Hill Companies srl
7
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Capitolo 4
Esecuzione di programmi C su macchine reali
Il C completo: dichiarazione delle variabili, stringhe di formato, direttiva #include.
Esercizio 4.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
Inserisci
Inserisci
Inserisci
Inserisci
Inserisci
Inserisci
numero:
numero:
numero:
numero:
numero:
numero:
numero:
6.25
-2.5
20
13.863
-15.625
4
38.192
Il rapporto (o il suo inverso) tra -2.5 e -15.625 vale 6.25
Soluzione dell’esercizio 4.1
#include <stdio.h>
main()
{
float dati[100], sum, rapp, inv_rapp;
int i, j, n_dati;
unsigned int trovata;
sum = 0;
n_dati = 0;
do
{
printf("Inserisci numero: ");
scanf("%f", &dati[n_dati]);
sum += dati[n_dati];
n_dati++;
} while (sum <= 50 && n_dati < 50);
trovata = 0;
if (n_dati >= 3)
{
i = 1;
while (trovata == 0 && i < n_dati - 1)
{
j = i+1;
while (trovata == 0 && j < n_dati)
{
if (dati[i] == 0 || dati[j] == 0)
Copyright © 2008 - The McGraw-Hill Companies srl
8
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
{
if (dati[0] == 0)
trovata = 1;
}
else
{
rapp = dati[i]/dati[j];
inv_rapp = dati[j]/dati[i];
if (rapp - dati[0] < 0.0000001 && rapp - dati[0] > -0.0000001 ||
inv_rapp - dati[0] < 0.0000001 && inv_rapp - dati[0] > -0.0000001)
trovata = 1;
}
if (trovata == 1)
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 4.2
Scrivere un programma C che esegua la seguente funzionalità. Si legge da tastiera una
sequenza di n interi positivi (massimo 100 numeri; la sequenza termina quando
l'utente inserisce il numero 0); dopo avere letto tutti i numeri, per ogni numero letto
viene stampato, ogni volta su una riga diversa e da sinistra verso destra, un numero di
asterischi pari al numero in questione.
Esempio di funzionamento del programma:
Inserisci
Inserisci
Inserisci
Inserisci
Inserisci
***
******
***
*****
numero
numero
numero
numero
numero
(0
(0
(0
(0
(0
per
per
per
per
per
terminare):
terminare):
terminare):
terminare):
terminare):
3
6
3
5
0
Soluzione esercizio 4.2
#include <stdio.h>
main()
{
unsigned int dati[100], dato_corr;
int i, j, n_dati;
n_dati = 0;
do
{
printf("Inserisci numero (0 per terminare): ");
scanf("%u", &dato_corr);
Copyright © 2008 - The McGraw-Hill Companies srl
9
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
if (dato_corr != 0)
{
dati[n_dati] = dato_corr;
n_dati++;
}
} while (dato_corr != 0 && n_dati < 100);
for( i=0 ; i<n_dati ; i++ )
{
for( j=0 ; j<dati[i] ; j++ )
printf("*");
printf("\n");
}
}
Esercizio 4.3
Scrivere un programma che legge da tastiera una sequenza di numeri interi e:
a) verifica che siano tutti non negativi (nel caso si trovi un numero negativo, il
programma dovrà terminare);
b) stampa a video:
a. la media dei numeri pari;
b. la media dei numeri dispari;
c. la media di tutti i numeri.
La sequenza sarà composta al massimo da 100 numeri.
Soluzione esercizio 4.3
#include <stdio.h>
main()
{
unsigned int i, num_dati;
int dati[100];
unsigned int negativo;
int media, somma, media_pari, somma_pari, media_dispari, somma_dispari;
int cont_pari, cont_dispari;
/* Lettura dei dati; massimo 100 dati*/
do
{
printf("Quanti numeri vuoi inserire?: ");
scanf("%u", &num_dati);
} while (num_dati == 0 || num_dati > 100);
for (i = 0; i < num_dati; i++)
{
printf("Inserisci numero (%u/%u): ", i + 1, num_dati);
scanf("%d", &dati[i]);
}
/* Controlla se i dati sono tutti non negativi */
negativo = 0;
i = 0;
while (i < num_dati && negativo == 0)
{
if (dati[i] < 0)
negativo = 1;
i = i + 1;
}
Copyright © 2008 - The McGraw-Hill Companies srl
10
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
/* Se i dati sono tutti non negativi, continua con l'elaborazione */
if (negativo == 0)
{
/* Calcola medie */
somma = 0;
somma_pari = 0;
somma_dispari = 0;
cont_pari = 0;
cont_dispari = 0;
for (i = 0; i < num_dati; i++)
{
somma = somma + dati[i];
/* L'operatore 'percentuale' calcola il resto */
/* della divisione intera, detto 'modulo' */
if (dati[i] % 2 == 0)
{
somma_pari = somma_pari + dati[i];
cont_pari = cont_pari + 1;
}
else
{
somma_dispari = somma_dispari + dati[i];
cont_dispari = cont_dispari + 1;
}
}
media = somma / num_dati;
media_pari = somma_pari / cont_pari;
media_dispari = somma_dispari / cont_dispari;
printf ("Media totale: %d\n", media);
printf ("Media numeri pari: %d\n", media_pari);
printf ("Media numero dispari: %d\n", media_dispari);
}
/* Se c'è almeno un numero negativo, termina l’esecuzione */
else
printf ("I numero devono essere tutti non negativi\n");
}
Esercizio 4.4
Si scriva un programma che calcola la media, il minimo e il massimo di una sequenza
di numeri reali letti dallo standard input; la sequenza viene terminata dal numero . I
valori risultanti devono essere scritti sullo standard output.
Soluzione dell'esercizio 4.4
#include <stdio.h>
main()
{
float x, s, min, max;
unsigned int n, num_dati;
printf("Quanti numeri vuoi inserire?: ");
scanf("%u", &num_dati);
s = 0.0;
for (n = 0; n < num_dati; n++)
{
printf ("Numero: ");
Copyright © 2008 - The McGraw-Hill Companies srl
11
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
scanf (“%f”, &x);
s = s + x;
if (n == 0)
{
min = x;
max = x;
}
else if (x < min)
min = x;
else if (x > max)
max = x;
}
if (n == 0)
printf ("nessun numero inserito");
else
printf ("La media è %f \n il minimo è %f \n il massimo è %f \n", s / n, min, max);
}
Copyright © 2008 - The McGraw-Hill Companies srl
12
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Capitolo 5
Tipi di dato
Inizializzazione delle variabili, definizione di nuovi tipi, puntatori, direttiva #define.
Esercizio 5.1
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 di tipo Giocattolo.
Si dichiarino successivamente due variabili, Giocattoli e Bambini, consistenti in due
array, rispettivamante di MAX_GIOCATTOLI elementi del tipo Giocattolo e
MAX_BAMBINI elementi del tipo Bambino. MAX_GIOCATTOLI e MAX_BAMBINI, 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 esercizio 5.1
#define MAX_GIOCATTOLI 20
#define MAX_BAMBINI 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[MAX_GIOCATTOLI];
Bambino Bambini[MAX_BAMBINI];
Copyright © 2008 - The McGraw-Hill Companies srl
13
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Esercizio 5.2
Si definiscano 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 esercizio 5.2
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 codiceFiscale[16];
} TipoDatiProprietario;
typedef struct
{
TipoDatiMotoveicolo motoveicolo;
TipoDatiProprietario proprietario;
} TipoVocePRA;
typedef struct
{
TipoVocePRA elementi[10000];
int nElementi;
} TipoPRA;
Copyright © 2008 - The McGraw-Hill Companies srl
14
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Esercizio 5.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 esercizo 5.3
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 5.4
Definire un tipo di dati che contiene le informazioni riguardanti un esame sostenuto
da un qualunque studente universitario.
Queste informazioni si compongono di: nome dell'esame (nessun nome è più lungo di
40 caratteri), codice alfanumerico (al massimo 6 lettere, per esempio AG0012), voto
compreso tra 18 e 30 e lode (si scelga un'opportuna rappresentazione dell'eventuale
lode, tenendo conto che non sono ammesse le frazioni di voto), numero di crediti
associati all'esame (sono ammesse le frazioni di credito, per esempio 7,5).
Di ogni studente si vogliono memorizzare le seguenti informazioni: nome (si suppone
che un nome non sia composto da più di 50 lettere), matricola (un numero naturale),
data di immatricolazione, numero di esami sostenuti, lista degli esami sostenuti (
essendo un singolo esame descritto come in precedenza(, media dei voti riportati.
Ogni studente può sostenere al massimo 29 esami.
(se si ritiene utile, si possono definire altri tipi di dati, di supporto a quelli richiesti)
Soluzione esercizio 5.4
typedef enum {false, true} boolean;
typedef struct
{
unsigned short giorno;
unsigned short mese;
unsigned int anno;
} Tipo_data;
typedef struct
{
char nome[40];
char codice[6];
unsigned short voto;
boolean lode;
Copyright © 2008 - The McGraw-Hill Companies srl
15
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
float crediti;
} Tipo_esame;
typedef struct
{
char nome[50];
unsigned int matricola;
Tipo_data data_immatricolazione;
Tipo_esame esami[29];
unsigned short numero_esami;
float media;
} Tipo_studente;
Esercizio 5.5
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 dell’esercizio 5.5
#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];
Copyright © 2008 - The McGraw-Hill Companies srl
16
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Esercizio 5.6
Si vuole scrivere un programma che tiene traccia del numero di CD acquistati per
ogni mese dell’anno nell’arco di 10 anni.
Definire un tipo TipoDatiCD che contiene i dati di ogni CD: il titolo (lungo al massimo
50 caratteri), l’autore (massimo 60 caratteri), l’anno di pubblicazione, il numero di
copie acquistate (anche più di una, se per esempio si vuole fare un regalo).
Definire un tipo di dato CDAcqInMese che contiene l’elenco dei CD comprati in un
dato mese (si può assumere che non vengano acquistati più di 50 diversi titoli al
mese) ed il numero di titoli diversi acquistati in quel mese.
Definire una variabile globale elencoCD che contiene l’elenco dei CD acquistati mese
per mese negli anni dal 1990 al 1999. Se si fa uso di tipi accessori, anche questi vanno
definiti.
Soluzione dell’esercizio 5.6
#include <stdio.h>
#define MAX_L_TITOLO 50
#define MAX_L_AUTORE 60
#define MAX_TIT_IN_MESE 50
typedef struct
{
char titolo[MAX_L_TITOLO];
char autore[MAX_L_AUTORE];
int anno;
int n_copie;
} TipoDatiCD;
typedef struct
{
TipoDatiCD cd[MAX_TIT_IN_MESE];
int n_titoli;
} CDAcqInMese;
/* Le righe di 'elencoCD' corrispondono agli anni dal 1990 al 1999,
le colonne ai 12 mesi di ciascun anno */
CDAcqInMese elencoCD[10][12];
Copyright © 2008 - The McGraw-Hill Companies srl
17
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Capitolo 6
Strutture di controllo
Strutture di controllo: for, switch, do-while.
Esercizio 6.1
Con riferimento all’esercizio 5.1, 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 “new line” (‘\n’) premendo il tasto <ENTER>
• 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 <ENTER>):
Immetti il nome di un bambino:
Giovanni
I giocattoli posseduti da Giovanni sono:
Trenino elettrico
Cavallo a dondolo
Soluzione dell’esercizio 6.1
#include <stdio.h>
#define ….
typedef ….
main ()
{
Giocattolo
Bambino
string
boolean
int
Giocattoli[MaxGiocattoli];
Bambini[MaxBambini];
NomeBambino;
trovato;
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”);
Copyright © 2008 - The McGraw-Hill Companies srl
18
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
i = 0;
scanf("%c", &NomeBambino[i]);
while (NomeBambino[i] != '\n')
{
i++;
scanf("%c", &NomeBambino[i])
}
LunghNomeBamb = i;
/* Si cerca nell’array Bambini il nome immesso */
trovato = false;
k = 0;
while (! trovato && k < NumBambini)
{
/* Si incrementa i fintanto che la condizione rimane vera */
for (i = 0; i <= LunghNomeBamb && Bambini[k].nome[i] == NomeBambino[i]; i++) ;
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 6.3
Realizzare un programma che legge da tastiera (e memorizza) una sequenza di
caratteri alfabetici minuscoli (letti ad uno ad uno), terminata dal carattere ‘#’; se
l’utente inserisce un carattere non valido (un carattere maiuscolo, un numero o un
simbolo che non sia ‘#’), il carattere non va memorizzato; la sequenza può essere
lunga al massimo 100 elementi (escluso lo ‘#’). Il programma riproduce sullo standard
output la sequenza di caratteri, convertendone il contenuto secondo la cifratura ROT13. Questa cifratura prevede che ad ogni carattere che rappresenta la lettera tra le 26
dell'alfabeto in posizione i si sostituisca la lettera in posizione i+13 (mod 26).
Ad esempio, digitando la sequenza di caratteri testodiprova#, il programma deve
stampare la stringa di caratteri grfgbqvcebin. Si noti come applicando un numero
pari di volte la trasformazione si riottenga il testo di partenza.
Soluzione dell’esercizio 6.3
#include <stdio.h>
#define MAX_NUM 100
main()
Copyright © 2008 - The McGraw-Hill Companies srl
19
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
{
char dati[MAX_NUM], dato_corr, trasf;
int i, j, n_dati;
n_dati = 0;
do {
printf("Inserisci carattere alfabetico (# per terminare, massimo %d caratteri): ",
MAX_NUM);
scanf(" %c", &dato_corr);
if (dato_corr <= 'z' && dato_corr >= 'a')
{
dati[n_dati] = dato_corr;
n_dati++;
}
} while (dato_corr != '#' && n_dati < MAX_NUM);
printf("\nSequenza trasformata:\n");
for(i = 0 ; i < n_dati ; i++)
{
trasf = 'a' + (dati[i]+13 - 'a') % 26;
printf("%c", trasf);
}
printf("\n");
}
Esercizio 6.4
Scrivere un programma che legge da tastiera delle righe di caratteri (di lunghezza
massima 100 caratteri). Per ogni riga letta, il programma conta il numero di
occorrenze di ogni vocale (sia che appaia in caratteri maiuscoli che in quelli
minuscoli).
Quando l'utente immette una riga vuota, il programma stampa un istogramma
verticale (dall'alto al basso) con tanti asterischi quante sono le occorrenze di ogni
vocale.
Per esempio, se l'utente immette le seguenti righe:
NEL mezzo DEL cammin DI nostra vita <ENTER>
mi RITROVAI per una SELVA oscura <ENTER>
CHE la diritta via era SMARRITA <ENTER>
<ENTER>
Il programma stampa il seguente istogramma:
AEIOU
*****
*****
****
****
***
***
***
* *
* *
* *
*
*
*
Copyright © 2008 - The McGraw-Hill Companies srl
20
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Soluzione dell’esercizio 6.4
#include <stdio.h>
#define MAX_RIGA 100
main()
{
char riga[MAX_RIGA+1];
unsigned int counter[5];
int i;
/* Inizializza i contatori */
for( i = 0 ; i < 5 ; i++ )
counter[i] = 0;
/* Leggi la prima riga */
printf("Inserisci riga di caratteri (max %d elementi):\n", MAX_RIGA);
i = 0;
scanf("%c", &riga[i]);
while (riga[i] != '\n')
{
i++;
scanf("%c", &riga[i]);
}
/* Analizza la riga */
while(riga[0] != '\n')
{
for( i=0 ; riga[i] != '\n' ; i++ )
{
if (riga[i] == 'a' || riga[i] == 'A')
counter[0] += 1;
else if (riga[i] == 'e' || riga[i] == 'E')
counter[1] += 1;
else if (riga[i] == 'i' || riga[i] == 'I')
counter[2] += 1;
else if (riga[i] == 'o' || riga[i] == 'O')
counter[3] += 1;
else if (riga[i] == 'u' || riga[i] == 'U')
counter[4] += 1;
}
/* Leggi la riga successiva */
printf("Inserisci riga di caratteri (max %d elementi):\n", MAX_RIGA);
i = 0;
scanf("%c", &riga[i]);
while (riga[i] != '\n')
{
i++;
scanf("%c", &riga[i]);
}
}
printf("\nAEIOU\n");
while ( counter[0] > 0 || counter[1] > 0 || counter[2] > 0 || counter[3] > 0 || counter[4] > 0 )
{
if (counter[0] > 0)
{
printf("*");
counter[0] -= 1;
}
else
{
Copyright © 2008 - The McGraw-Hill Companies srl
21
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
printf(" ");
}
if (counter[1] > 0)
{
printf("*");
counter[1] -= 1;
}
else
{
printf(" ");
}
if (counter[2] > 0)
{
printf("*");
counter[2] -= 1;
}
else
{
printf(" ");
}
if (counter[3] > 0)
{
printf("*");
counter[3] -= 1;
}
else
{
printf(" ");
}
if (counter[4] > 0)
{
printf("*");
counter[4] -= 1;
}
else
{
printf(" ");
}
printf("\n");
}
}
Esercizio 6.5
Facendo riferimento all’Esercizio 5.5, si scriva 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 dell’esercizio 6.5
main()
{
Copyright © 2008 - The McGraw-Hill Companies srl
22
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
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 6.6
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.
Copyright © 2008 - The McGraw-Hill Companies srl
23
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Soluzione dell’esercizio 6.6
#define MAX_PACC 64
typedef int TipoPacchetto[4];
typedef enum {false, true} boolean;
main()
{
TipoPacchetto corretti[MAX_PACC], non_corretti[MAX_PACC], corrente;
int i, j, k, h, somma, n_corretti, n_non_corretti;
boolean 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;
Copyright © 2008 - The McGraw-Hill Companies srl
24
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
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 6.7
Con riferimento all’Esercizio 5.6, si scriva un main() che, senza curarsi di come viene
inizializzata la variabile elencoCD (che supponiamo già caricata con i dati di
interesse), esegue le seguenti operazioni:
- chiede all’utente di inserire un anno (compreso tra 1990 e 1999);
- per ogni trimestre di quell’anno (Gen-Mar, Apr-Giu, Lug-Set, Ott-Dic) stampa
a video il numero di CD (contando anche le copie multiple dello stesso titolo)
acquistati in quel periodo.
Soluzione dell’esercizio 6.7
#include <stdio.h>
#define MAX_L_TITOLO 50
#define MAX_L_AUTORE 60
#define MAX_TIT_IN_MESE 50
typedef struct
{
char titolo[MAX_L_TITOLO];
char autore[MAX_L_AUTORE];
int anno;
int n_copie;
} TipoDatiCD;
typedef struct
{
TipoDatiCD cd[MAX_TIT_IN_MESE];
int n_titoli;
} CDAcqInMese;
/* Le righe di 'elencoCD' corrispondono agli anni dal 1990 al 1999,
le colonne ai 12 mesi di ciascun anno */
CDAcqInMese elencoCD[10][12];
main()
Copyright © 2008 - The McGraw-Hill Companies srl
25
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
{
int anno;
int i, j, k, totale_cd_trimestre;
do
{
printf("Inserisci un anno compreso tra 1990 e 1999: ");
scanf("%d", &anno);
} while (anno < 1990 || anno > 1999);
/* tramuto l'anno interno nella riga corrspondente dell'array doppio 'elencoCD' */
anno = anno - 1990;
/* il ciclo piu' esterno conta i trimestri, quello piu' interno i
mesi del trimestre */
for(i = 0 ; I < 4 ; i++)
{
totale_cd_trimestre = 0;
for(j = 0 ; j < 3 ; j++)
{
/* conto il numero di CD acquistati nel mese i*3+j e li aggiungo
al totale del trimestre*/
for(k = 0 ; k < elencoCD[anno][i*3+j].n_titoli ; k++)
{
totale_cd_trimestre += elencoCD[anno][i*3+j].cd[k].n_copie;
}
}
printf("Totale CD del trimestre n. %d dell'anno %d: %d\n", i+1, anno+1990,
totale_cd_trimestre);
}
}
Copyright © 2008 - The McGraw-Hill Companies srl
26
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Capitolo 7
Funzioni e procedure
Funzioni e procedure, parametri e valore di ritorno; stringhe.
Esercizio 7.1
Si consideri la seguente dichiarazione di tipo:
typedef struct
{
int campo1;
int campo2;
int campo3;
int campo4;
} Struttura;
Parte 1. Si scriva una funzione che riceva un parametro di tipo Struttura e produca
come risultato un valore dello stesso tipo in cui i campi risultino invertiti (il valore di
campo4 si trovi in campo1 e quello di campo3 in campo2).
Parte 2. Si trasformi poi la funzione in una procedura che esegua la medesima
operazione sulla variabile di tipo struttura che le è passata come parametro.
Soluzione dell’esercizio 7.1
Parte 1.
Struttura InvertiStruttura (Struttura param)
{
Struttura varloc;
varloc.campo1 = param.campo4;
varloc.campo2 = param.campo3;
varloc.campo3 = param.campo2;
varloc.campo4 = param.campo1;
return varloc;
}
Parte 2.
void ProcInvertiStruttura (Struttura *param)
{
Struttura varloc;
varloc.campo1 = param->campo4;
varloc.campo2 = param->campo3;
varloc.campo3 = param->campo2;
varloc.campo4 = param->campo1;
param->campo4 = varloc.campo4;
param->campo3 = varloc.campo3;
param->campo2 = varloc.campo2;
param->campo1 = varloc.campo1;
}
Copyright © 2008 - The McGraw-Hill Companies srl
27
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Esercizio 7.2
Data la seguente funzione calcola():
int calcola( int *a, int b, int *c)
{
*a = *a * 2;
b = b * 2;
*c = *c - 2;
return *a + b + *c;
}
Qual è l'output del seguente frammento di programma?
main()
{
int z;
int *y;
int x;
y = &x;
z = 1;
*y = 2;
x = 3;
z = calcola(&z,x,y);
printf("%d, %d",z,x);
}
Soluzione dell’esercizio 7.2
Il frammento di programma stampa, nell’ordine, i valori 9, 1. Infatti, prima della
chiamata di calcola(), z ha valore 1, y contiene l’indirizzo di x, ed x vale 3 (quindi *y
vale anch’esso 3).
Durante l’esecuzione di calcola(), x passa da 3 ad 1 con l’istruzione *c = *c – 2.
z viene anch’esso modificato (è passato per indirizzo), ma questa modifica viene poi
annullata quando, al termine di calcola(), il valore ritornato dalla funzione è assegnato
a z. Poichè calcola() ritorna 9 (la funzione era stata chiamata con z=1, x=3, *y=3), z alla
fine vale 9.
Esercizio 7.3
Data la seguente funzione calcola():
int calcola(int *a, int b, int *c)
{
*a = *a * b;
b = b * 2;
*c = *a - b;
return *a + b + *c;
}
Ed il seguente programma:
main()
{
int z;
int *y;
Copyright © 2008 - The McGraw-Hill Companies srl
28
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
int x;
y = &x;
z = -1;
*y = 1;
x = 2;
z = calcola(y,x,&z);
}
Mostrare lo stato delle variabili x, y e z al termine dell'invocazione di calcola().
Soluzione dell’esercizio 7.3
Alla fine del main(), la variabile x contiene il valore 4, la y punta a x, quindi *y a sua
volta vale 4, mentre z vale 8. Infatti, prima della chiamata di calcola, z ha valore -1, y
contiene l’indirizzo di x, ed x vale 2 (quindi *y vale anch’esso 3).
Durante l’esecuzione di calcola(), x passa da 2 ad 4 con l’istruzione *a = *a * b.
z viene anch’esso modificato (è passato per indirizzo), ma questa modifica viene poi
annullata quando, al termine di calcola(), il valore ritornato dalla funzione è assegnato
a z. Poichè calcola ritorna 8 (la funzione era stata chiamata con z=-1, x=2, *y=2), z alla
fine vale 8.
Esercizio 7.4
Si scriva un insieme di dichiarazioni di tipo per la rappresentazione dello stato di un
apparecchio TV. Esso deve contenere una descrizione dello stato del televisore
(acceso/spento, canale, posizione dei vari controlli: luminosità, volume, ecc.).
Si scrivano poi i prototipi (non le definizioni complete) di alcune funzioni
corrispondenti ai comandi. Ad esempio, una funzione cambiaCanale() potrebbe
assegnare al televisore il canale impostato dall’utente; un’ulteriore funzione
incrementaCanale(), innescata dalla pressione del tasto corrispondente, dovrebbe
determinare il passaggio dal canale attuale al successivo; ecc.
Successivamente si scrivano le definizioni di almeno due delle procedure suddette.
Soluzione dell’esercizio 7.4
#include <stdio.h>
#define INCREMENTO 0.1
typedef enum {false, true} boolean;
typedef struct
{
boolean acceso;
unsigned int canale;
float luminosita;
float saturazione;
float volume;
} Televisore;
/* Tra 0 e 1 */
/* Tra 0 e 1 */
/* Tra 0 e 1 */
/* Prototipi delle funzioni */
void cambiaCanale (Televisore *stato, unsigned int nuovoCanale);
void accendiSpegni (Televisore *stato);
void incrementaCanale (Televisore *stato);
void decrementaCanale (Televisore *stato);
void incrementaVolume (Televisore *stato);
Copyright © 2008 - The McGraw-Hill Companies srl
29
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
void decrementaVolume (Televisore *stato);
void incrementaSaturazione (Televisore *stato);
void decrementaSaturazione (Televisore *stato);
void incrementaLuminosita (Televisore *stato);
void decrementaLuminosita (Televisore *stato);
main()
{
Televisore stato;
/* Per esempio, accendiamo e spegniamo il televisore */
stato.acceso = false;
printf ("%d", stato.acceso);
accendiSpegni (&stato);
printf ("%d", stato.acceso);
accendiSpegni (&stato);
printf ("%d", stato.acceso);
}
/* Definizione delle funzioni */
void incrementaCanale (Televisore *stato)
{
if (stato->canale < 99)
stato->canale = stato->canale + 1;
}
void incrementaVolume (Televisore *stato)
{
if (stato->volume + INCREMENTO <= 1)
stato->volume = stato->volume + INCREMENTO;
}
void accendiSpegni (Televisore *stato)
{
stato->acceso = ! stato->acceso;
}
… definizione delle funzioni rimanenti.
Esercizio 7.5
Si scriva un programma che:
• Legge dallo standard input una sequenza di coppie di numeri reali {<xi,yi>} (per
comodità si può assumere che tale sequenza non contenga più di KMAX elementi,
essendo KMAX un valore costante noto a priori).
• Per ogni coppia <xi,yi> calcola il valore zi della funzione f(xi,yi) = 20⋅x2i - y3i.
• Stampare sullo standard output la sequenza di valori { zi } in ordine crescente.
Ad esempio, in corrispondenza della sequenza di input {<0,5>, <2,4>, <1,3>} il
programma deve stampare in uscita la sequenza {-125, -7, 16}
E’ particolarmente apprezzata la costruzione di un programma che sia facilmente
modificabile in modo da risolvere lo stesso problema facendo però riferimento ad una
diversa funzione f(xi,yi) (ad esempio f(xi,yi) = sin(xi). cos3(yi))
Se lo si ritiene opportuno è possibile fare uso di adeguati sottoprogrammi di servizio
(ad esempio una procedura di ordinamento) senza codificarli ma limitandosi a
dichiararne opportunamente l’interfaccia.
Soluzione dell’esercizio 7.5
#include <stdio.h>
Copyright © 2008 - The McGraw-Hill Companies srl
30
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
#define KMAX 10
typedef struct
{
float x;
float y;
} Coppia;
/* Dichiarazione prototipi */
float eleva (float base, unsigned int esp);
float funzione (Coppia c);
void ordina (float ris[], unsigned int n);
main()
{
float risultati[KMAX];
unsigned int nCoppie, i;
Coppia c;
printf ("Quante coppie (max %u): ", KMAX);
scanf ("%u", &nCoppie);
for (i = 0; i < nCoppie; i++)
{
printf ("x: ");
scanf ("%f", &c.x);
printf ("y: ");
scanf ("%f", &c.y);
risultati[i] = funzione(c);
}
ordina (risultati, nCoppie);
for (i = 0; i < nCoppie; i++)
printf ("risultato: %f\n", risultati[i]);
}
/* Definizione delle funzioni */
/* Si assume che la funzione ordina() sia fornita dall'esterno */
float eleva (float base, unsigned int esp)
{
unsigned int i;
float tot = 1.0;
for (i = 0; i < esp; i++)
tot = tot * base;
return tot;
}
float funzione (Coppia c)
{
return 20 * eleva (c.x, 2) - eleva (c.y, 3);
}
Copyright © 2008 - The McGraw-Hill Companies srl
31
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Capitolo 8
Introduzione alla programmazione ricorsiva
La ricorsione.
Esercizio 8.1
E’ data la funzione ricorsiva:
int elabora(int n1, int n2)
{
int a, b;
a = n1 + 1;
b = n2 - 1;
if (b <= 0)
return a;
else
return alabora(a,b);
}
Descrivere l'esecuzione della funzione in seguito all'invocazione: elabora(4,3).
Soluzione dell’esercizio 8.1
La sequenza di chiamate ricorsive della funzione elabora() è la seguente:
elabora(4,3)
elabora(5,2)
elabora(6,1)
Alla fine il valore ritornato dalla chiamata elabora(4,3) è 7.
Esercizio 8.2
Sia data la funzione ricorsiva seguente:
void elabora(unsigned int i)
{
if (i <= 1)
printf("%u\n", i);
else
{
printf("%u", i % 2);
elabora(i / 2);
}
}
Descrivere l'esecuzione della funzione in seguito all'invocazione elabora(10),
specificando che cosa rimane visualizzato sullo schermo alla fine dell’esecuzione.
Soluzione dell’esercizio 8.2
La sequenza di chiamate ricorsive della funzione elabora() è la seguente:
elabora(10)
Copyright © 2008 - The McGraw-Hill Companies srl
32
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
elabora(5)
elabora(2)
elabora(1)
Alla fine rimane visualizzata la seguente sequenza di valori: 0101. La funzione
Elabora infatti calcola in maniera ricorsiva la rappresentazione binaria (scritta con la
cifra meno significativa a sinistra) del numero passatole.
Esercizio 8.3
Si consideri la seguente funzione, che calcola l’n-simo numero di Fibonacci in modo
ricorsivo:
int fibonacci(unsigned int n)
{
if (n == 0)
return 0;
else if (n == 1)
return 1;
else
return fib(n – 1) + fib(n – 2);
}
Si descriva la computazione di fib(4).
Soluzione dell’esercizio 8.3
La sequenza di chiamate ricorsive della funzione fibonacci() è la seguente:
fibonacci(4)
fibonacci(3) + fibonacci(2)
fibonacci(2) + fibonacci(1) + fibonacci(1) + fibonacci(0)
fibonacci(1) + fibonacci(0) + 1 + 1 + 0
1+0+1+1+0
3
Esercizio 8.4
Data la seguente definizione ricorsiva:
f(x) = 0;
f(x) = 2 + f(f(x-2)-2);
per x = 0
per x > 0
1. Si determini per quali valori interi di x è definita la funzione e quale è il suo
valore.
2. Si scriva una funzione ricorsiva che realizzi la funzione stessa. Il prototipo
della funzione sia il seguente:
int f1 (int x);
3. Si scriva una funzione che realizzi la funzione e restituisca come parametro il
numero di chiamate ricorsive effettuate. Il prototipo della funzione sia il
seguente:
int f2 (int x, int *numChiamate);
Copyright © 2008 - The McGraw-Hill Companies srl
33
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
NB: si supponga che, al momento della prima chiamata, il valore di
numChiamate sia correttamente inizializzato a 0.
Soluzione dell’esercizio 8.4
Parte 1.
La funzione è definita solo per x = 0.
Parte 2.
int f1(int x)
{
if (x == 0)
return 0;
else if (x > 0)
return 2 + f(f(x-2)-2);
else
{
printf ("ERRORE x=%d\n", x);
exit();
}
}
Parte 3.
int f2(int x, int *numChiamate)
{
*numChiamate = *numChiamate + 1;
if (x == 0)
return 0;
else if (x > 0)
return 2 + f(f(x-2, numChiamate)-2, numChiamate);
else
{
printf ("ERRORE x=%d, nunChiamate=%d\n", x, *numChiamate);
exit();
}
}
Copyright © 2008 - The McGraw-Hill Companies srl
34
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Capitolo 9
Gestione dei file
I file di testo e i file binari.
Esercizio 9.1
Con riferimento all’esercizio 5.4 si scriva la funzione inserisciMedia() che legge un
file binario contenente i dati di tutti gli studenti di un ateneo, privi della media dei
voti riportati e lo aggiorna inserendo nell’apposito campo la media suddetta.
La funzione dovrà a sua volta far uso di un’ulteriore, appropriata, funzione che calcoli
la media. E’ sufficiente fornire la dichiarazione di tale funzione ausiliaria, senza
fornirne la definizione completa.
Soluzione dell’esercizio 9.1
#include <stdio.h>
typedef enum {false, true} boolean;
typedef struct
{
unsigned short giorno;
unsigned short mese;
unsigned int anno;
} Tipo_data;
typedef struct
{
char nome[40];
char codice[6];
unsigned short voto;
boolean lode;
float crediti;
} Tipo_esame;
typedef struct
{
char nome[50];
unsigned int matricola;
Tipo_data data_immatricolazione;
Tipo_esame esami[29];
unsigned short numero_esami;
float media;
} Tipo_studente;
/* La funzione media() non viene implementata */
float media (Tipo_esame esami[], unsigned short numEsami);
void inserisciMedia(char nomeFIle[]);
main()
{
/* Il main del programma... */
}
Copyright © 2008 - The McGraw-Hill Companies srl
35
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
void inserisciMedia(char nomeFile[])
{
FILE *fileDati;
Tipo_studente studente;
fileDati = fopen(nomeFile, "r+");
fread (&studente, sizeof(studente), 1, fileDati);
while (! feof(fileDati))
{
studente.media = media (studente.esami, studente.numero_esami);
fread (&studente, sizeof(studente), 1, fileDati);
/* Torna indietro per scrivere le modifche sullo stesso record */
fseek (fileDati, -sizeof(studente), SEEK_CUR);
fwrite (&studente, sizeof(studente), 1, fileDati);
}
fclose (fileDati);
}
Esercizio 9.2
Con riferimento all’Esercizio 5.5 si definiscano i tipi TipoStrumentista e TipoQuartetto
come nell'esercizio suddetto.
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.
Si supponga poi 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 a scelta una delle seguenti varianti.
Variante a
Dopo avere
dichiarato
Variante b
Dopo avere
dichiarato
Variante c
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.
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.
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.
Copyright © 2008 - The McGraw-Hill Companies srl
36
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Suggerimento per le varianti b e c: per troncare un file f alla lunghezza data dalla
posizione corrente nel file, l’istruzione da usare è: ftruncate(fileno(f), ftell(f));
Soluzione dell’esercizio 9.2
Definizione dei tipi; parte comune a tutte le varianti.
#define L_NOME_MUS 40
#define L_NOME_QUAR 30
#define MAX_QUARTETTI 100
#define L_NOME_CONC 40
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;
typedef struct
{
char nome_loc[L_NOME_CONC + 1];
TipoData data;
TipoQuartetto quartetto;
} TipoConcerto;
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))
Copyright © 2008 - The McGraw-Hill Companies srl
37
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
{
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;
}
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);
Copyright © 2008 - The McGraw-Hill Companies srl
38
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
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;
}
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 posizione corrente nel file
perchè a questa posizione dovrò poi tornare per ricominciare a leggere. */
pos_next_read = ftell(f_concerti);
/* mi sposto nel file alla posizione in cui devo scrivere, e poi effettivamente scrivo. */
if (fseek(f_concerti, pos_next_write, SEEK_SET))
return 0;
if (fwrite(&curr_conc, sizeof(TipoConcerto), 1, f_concerti) != 1)
return 0;
Copyright © 2008 - The McGraw-Hill Companies srl
39
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
/* 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 9.3
Si abbia un file (binario) “FileFatture.dat” 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 dell’esercizio 9.3
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);
Copyright © 2008 - The McGraw-Hill Companies srl
40
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
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 9.4
Si scriva un programma che legge un file di parole appartenenti al vocabolario
italiano o al vocabolario inglese e le ristampa su due file separati, uno per le parole
inglesi e uno per quelle italiane.
Si assuma che il programma abbia accesso (in memoria o su file) ai vocabolari delle
due lingue.
NB1. Si ponga attenzione a casi particolari come il fatto che una parola del file
originario non si trovi in nessuno dei due vocabolari o che si trovi in entrambi, ecc.
NB2. Non è necessaria una codifica in tutti i dettagli del programma completo: si può
invece far uso di opportune procedure limitandosi a definire con precisione il loro uso
(la loro interfaccia) senza per questo codificarne l'implementazione.
Soluzione dell’esercizio 9.4
#include <stdio.h>
typedef enum {false, true} boolean;
/* Le funzioni inVocabolarioItaliano() e inVocabolarioInglese() non sono implementate… */
boolean inVocabolarioItaliano (char parola[]);
boolean inVocabolarioInglese (char parola[]);
void separaParoleItaIng (char nomeFilePar[], char nomeFileParIta[], char nomeFileParIng[]);
main()
{
char nomeFileParole[100], nomeFileParoleIta[100], nomeFileParoleIng[100];
printf ("Nome file di parole: ");
scanf ("%s", nomeFileParole);
printf ("Nome file di parole italiane: ");
scanf ("%s", nomeFileParoleIta);
printf ("Nome file di parole inglesi: ");
scanf ("%s", nomeFileParoleIng);
separaParoleItaIng (nomeFileParole, nomeFileParoleIta, nomeFileParoleIng);
}
/* Si assume che una parola non sia lunga più do 50 lettere */
/* Se la parola esiste in entrambi i vocabolari, viene scritta in entrambi i file */
void separaParoleItaIng (char nomeFilePar[], char nomeFileParIta[], char nomeFileParIng[])
{
FILE *fileParole, *fileParoleIta, *fileParoleIng;
char parola[50];
fileParole = fopen (nomeFilePar, "r");
fileParoleIta = fopen (nomeFileParIta, "w");
fileParoleIng = fopen (nomeFileParIng, "w");
fscanf (fileParole, "%s", parola);
while (! feof (fileParole))
Copyright © 2008 - The McGraw-Hill Companies srl
41
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
{
if (inVocabolarioItaliano (parola))
fprintf (fileParoleIta, "%s\n", parola);
if (inVocabolarioInglese (parola))
fprintf (fileParoleIng, "%s\n", parola);
fscanf (fileParole, "%s", parola);
}
fclose (fileParole);
fclose (fileParoleIta);
fclose (fileParoleIng);
}
Copyright © 2008 - The McGraw-Hill Companies srl
42
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Capitolo 10
Strutture dati dinamiche
Le liste.
Esercizio 10.1
Parte a.
Si considerino la tradizionale dichiarazione:
struct EL
{
int Info;
struct EL *Prox;
};
typedef struct EL ElemLista;
typedef ElemLista *ListaDiInteri;
E la seguente funzione:
int sconosciuta (ListaDiInteri Lista)
{
int x = 0;
ListaDiInteri cursore;
cursore = Lista;
while (cursore != NULL)
{
if (cursore->Info > x)
x = cursore->Info;
cursore = cursore->Prox;
}
return x;
}
Si dica qual’è il risultato della funzione sconosciuta quando vengono eseguite le
seguenti chiamate:
sconosciuta (L1)
sconosciuta (L2)
L1 ed L2 essendo, rispettivamente le liste rappresentate nella figura seguente.
Copyright © 2008 - The McGraw-Hill Companies srl
43
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
L1
6
4
18
-4
4
L2
In generale, qual’è il risultato prodotto dalla funzione per una generica lista di interi?
Parte b.
Si ricodifichi la funzione sconosciuta in forma ricorsiva.
Soluzione dell’esercizio 10.1
Parte a.
La funzione produce come risultato 18, quando applicata alla lista L1 e 0 quando
applicata a L2. In generale essa il valore massimo contenuto nella lista se essa
contiene almeno un numero positivo; 0 in caso contrario (lista vuota o contenente solo
numeri non positivi).
Parte b.
Si definisca in primo luogo la funzione ausiliaria max():
Int max(int p1, p2)
{
if (p1 > p2)
return p1;
else
return p2;
}
Successivamente la funzione sconosciuta può essere ricodifcata come segue, in forma
ricorsiva:
int sconosciuta (ListaDiInteri Lista)
/*la funzione produce il valore massimo contenuto nel parametro Lista se essa contiene
almeno un numero positivo; 0 in caso contrario */
{
if (Lista == NULL)
return 0;
else
return (max(Lista->Info, sconosciuta(Lista->Prox));
}
Copyright © 2008 - The McGraw-Hill Companies srl
44
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Esercizio 10.2
Si vuole realizzare una serie di funzioni per la manipolazione di un archivio di numeri
di carte di credito. Ogni carta di credito è definita dai seguenti dati: nome del titolare
della carta (massimo 80 caratteri), numero della carta di credito (un codice di
esattamente 16 cifre), massimale di spesa mensile per la carta (in euro).
Il programma deve essere sviluppato nei seguenti punti:
Punto a.
Definire il tipo TipoCartaDiCredito, che contiene i dati di una singola carta. Definire
quindi i tipi TipoElemListaCarte e TipoListaCarte (con l’ovvio significato degli
identificatori), necessari per definire una lista di carte di credito realizzata mediante
puntatori.
Dichiarare i prototipi di tutte e sole le seguenti funzioni (senza darne ancora
l’implementazione!):
• carica_lista_da_file(): riceve in ingresso il nome del file binario in cui è
memorizzato l’archivio e ritorna una lista contente i dati dell’archivio; si assuma
che il file binario contenga una sequenza di dati TipoCartaDiCredito; la lista
ritornata dalla funzione non è ordinata secondo nessun criterio particolare; se non
è possibile recuperare i dati da file, la funzione ritorna una lista vuota;
• scarica_lista_su_file(): riceve in ingresso una lista di carte di credito ed un nome di
file, e scrive la lista nel dato file; se il file già esiste, viene cancellato, altrimenti
viene creato ex-novo; la funzione ritorna 1 se la scrittura avviene con successo, 0
altrimenti;
• stampa_ListaCarte(): riceve in ingresso una lista di carte di credito, e la stampa a
video;
• estrai_carte_da_lista(): riceve in ingresso una lista di carte di credito, e ne ritorna
una nuova, che contiene solo le carte di credito la cui ultima cifra è ‘7’.
Punto b.
Implementare la funzione carica_lista_da_file() dichiarata al punto a). Eventuali librerie
standard del C usate per implementare la funzione vanno dichiarate prima del corpo
della funzione stessa, mediante l’apposita clausola include. Eventuali ulteriori
sottoprogrammi ausiliari dovranno essere definiti completamente.
Punto c
Implementare la funzione estrai_carte_da_lista dichiarata al Punto a. Eventuali librerie
standard del C usate per implementare la funzione vanno dichiarate prima del corpo
della funzione stessa, mediante l’apposita clausola #include. Eventuali ulteriori
sottoprogrammi ausiliari dovranno essere definiti completamente.
Si fornisca una duplice implementazione della funzione: una versione iterativa e una
ricorsiva.
Copyright © 2008 - The McGraw-Hill Companies srl
45
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Soluzione dell’esercizio 10.2
Punto a.
#define MAX_L_NOME 80
typedef struct
{
char nome[MAX_L_NOME+1];
char numero[16];
float massimale;
} TipoCartaDiCredito;
struct EL
{
TipoCartaDiCredito info;
struct EL *next;
};
typedef struct EL TipoElemListaCarte;
typedef TipoElemListaCarte *TipoListaCarte;
TipoListaCarte carica_lista_da_file (char *nome_file);
int scarica_lista_su_file (char *nome_file, TipoListaCarte lista);
void stampa_ListaCarte (TipoListaCarte lista);
TipoListaCarte estrai_carte_da_lista (TipoListaCarte lista);
Punto b.
#include <stdlib.h>
TipoListaCarte carica_lista_da_file (char *nome_file)
{
FILE *f;
TipoCartaDiCredito carta;
TipoElemListaCarte *ptr_el;
TipoListaCarte l = NULL;
f = fopen(nome_file, “rb+”);
if(f == NULL)
return NULL;
while (fread(&carta, sizeof(TipoCartaDiCredito), 1, f) == 1)
{
ptr_el = malloc(sizeof(TipoElemListaCarte));
ptr_el->info = carta;
ptr_el->next = l;
l = ptr_el;
}
return l;
}
Punto c (versione iterativa).
#include <stdlib.h>
TipoListaCarte estrai_carte_da_lista (TipoListaCarte lista)
{
TipoListaCarte new_l = NULL;
Copyright © 2008 - The McGraw-Hill Companies srl
46
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
TipoElemListaCarte *curr = lista, *ptr_new_el;
while (curr != NULL)
{
if (curr->info.numero[16] == ‘7’)
{
ptr_new_el = malloc(sizeof(TipoElemListaCarte));
ptr_new_el->info = curr->info;
ptr_new_el->next = new_l;
new_l = ptr_new_el;
}
curr = curr->next;
}
return new_l;
}
Punto c (versione ricorsiva).
#include <stdlib.h>
TipoListaCarte estrai_carte_da_lista (TipoListaCarte lista)
{
TipoElemListaCarte *ptr_new_el = NULL;
if (lista == NULL)
return NULL;
if (lista->info.numero[16] == ‘7’)
{
ptr_new_el = malloc(sizeof(TipoElemListaCarte));
ptr_new_el->info = lista->info;
ptr_new_el->next = estrai_carte_da_lista(lista->next);
return ptr_new_el;
}
else
return estrai_carte_da_lista(lista->next);
}
Esercizio 10.3
Si vuole realizzare un programma GestisciNomi che realizza le seguenti funzionalità:
• legge dal file “ElencoNomi” un elenco di nomi (ogni nome si trova su una riga
separata);
• man mano che i nomi vengono letti, essi vengono inseriti in una lista, la quale
viene mantenuta ordinata secondo l’ordine alfabetico;
• quando non ci sono più nomi da leggere dal file, la lista viene stampata a video;
• viene creata una nuova lista, che contiene gli stessi elementi della precedente, ma
in ordine inverso rispetto all’originale (NB: la lista originale deve essere lasciata
inalterata);
• la lista inversa viene stampata.
Si precisa che il file da cui vengono letti i nomi è in formato carattere (non binario!),
con ogni nome su una riga diversa; si presume che non ci siano righe vuote. Ogni riga
è lunga al massimo 80 caratteri.
Il programma deve essere sviluppato nei seguenti punti:
Punto a.
Definire i tipi TipoElemListaNomi e TipoListaNomi (con l’ovvio significato degli
identificatori), quindi dichiarare i prototipi di tutte e sole le seguenti funzioni (senza
darne ancora l’implementazione!):
Copyright © 2008 - The McGraw-Hill Companies srl
47
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
•
•
•
•
Esercizi
init_ListaNomi(): inizializza una lista di nomi alla lista vuota;
inserisci_nome(): riceve in ingresso un nome ed una lista di nomi, ed inserisce il
nome nella lista, in modo che la lista rimanga ordinata in ordine alfabetico; se
l’inserimento avviene con successo ritorna true, altrimenti false;
stampa_ListaNomi(): riceve in ingresso una lista di nomi, e la stampa a video nome
per nome, riga per riga;
inverti_ListaNomi(): riceve in ingresso una lista di nomi, e ne ritorna una nuova, in
cui l’ordine degli elementi nella lista è invertito.
Punto b.
Scrivere un main che, utilizzando le funzioni dichiarati al punto precedente (e la
libreria standard del C; le librerie che vengono usate devono essere indicate con
l’apposita clausola #include prima del main), realizza il programma GestisciNomi
delineato in precedenza.
Punto c.
Implementare la funzione (e solo quella!) inverti_ListaNomi() dichiarata al Punto a.
Eventuali librerie standard del C usate per implementare la funzione vanno dichiarate
prima del corpo della funzione stessa, mediante l’apposita clausola #include. Eventuali
ulteriori sottoprogrammi ausiliari dovranno essere definiti completamente.
La funzione inverti_ListaNomi() deve essere implementata sia in versione iterativa che
in versione ricorsiva.
Soluzione dell’esercizio 10.3
Punto a.
#define MAX_L_NOME 80
struct EL
{
char info[MAX_L_NOME + 1];
struct EL *next;
};
typedef struct EL TipoElemListaNomi;
typedef TipoElemListaNomi *TipoListaNomi;
typedef enum {false, true} boolean;
void init_ListaNomi (TipoListaNomi *lista_I);
boolean inserisci_nome (char nome[], TipoListaNomi *lista_Ins);
void stampa_ListaNomi (TipoListaNomi lista_S);
TipoListaNomi inverti_ListaNomi(TipoListaNomi lista_Inv);
Punto b.
#include <stdio.h>
main()
{
TipoListaNomi lista_Att, inversa;
char nome[MAX_L_NOME + 1];
FILE *f;
f = fopen(“ElencoNomi”, “r”);
if(f == NULL)
Copyright © 2008 - The McGraw-Hill Companies srl
48
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
printf(“Errore nell’apertura del file\n”);
else
{
init_ListaNomi(&lista_Att);
while (! feof(f))
{
fgets(nome, MAX_L_NOME + 1, f);
inserisci_nome(nome, &lista_Att);
}
stampa_ListaNomi(lista_Att);
inversa = inverti_ListaNomi(lista_Att)
stampa_ListaNomi(inversa);
}
}
Punto c (versione iterativa).
#include <stdlib.h>
#include <string.h>
TipoListaNomi inverti_ListaNomi (TipoListaNomi lista_Inv)
{
TipoListaNomi inversa;
TipoElemListaNomi *cursor, *temp;
init_ListaNomi(&inversa);
cursor = lista_Inv;
while(cursor != NULL)
{
temp = malloc(sizeof(TipoElemListaNomi));
strcpy(temp->info, cursor->info);
temp->next = inversa;
inversa = temp;
cursor = cursor->next;
}
return inversa;
}
Punto c (versione ricorsiva).
#include <stdlib.h>
#include <string.h>
void inserisci_in_coda(TipoListaNomi *lista, char nome[])
{
TipoElemListaNomi *temp;
if (lista == NULL)
{
temp = malloc(sizeof(TipoElemListaNomi));
temp->next = NULL;
strcpy(temp->info, (*lista)->info);
*lista = temp;
}
else
inserisci_in_coda(&((*lista)->next), nome);
}
TipoListaNomi inverti_ListaNomi (TipoListaNomi lista_Inv)
Copyright © 2008 - The McGraw-Hill Companies srl
49
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
{
TipoElemListaNomi *inversa;
if(lista == NULL)
return NULL;
else
{
inversa = inverti_ListaNomi(lista_Inv->next);
inserisci_in_coda(&inversa, lista_Inv->info);
return inversa;
}
}
Esercizio 10.4
Si considerino le seguenti dichiarazioni:
/* xxx denota una qualsiasi dichiarazione del tipo TipoElemento che qui non interessa
Sull’insieme dei valori di TipoElemento è definita una relazione d’ordine totale
implementata dalla funzione precede() dichiarata in seguito*/
typedef xxx TipoElemento;
typedef enum {false, true} boolean;
/* precede() ritorna true o false a seconda che elem1 preceda o no elem2
nella relazione d’ordine definita su TipoElemento*/
boolean precede (TipoElemento elem1, TipoElemento elem2);
Punto a.
Si definiscano i tipi TipoElementoLista e TipoLista per costruire liste di elementi di tipo
TipoElemento basate su puntatori.
Punto b.
Si scriva una funzione merge(), codificandola sia in modo ricorsivo che iterativo, che
riceva come parametri due liste ordinate in ordine crescente rispetto alla relazione
implementata dalla funzione precede (l’i-esimo elemento precede l’i+1-esimo)
contenenti elementi del tipo TipoElemento e produce come risultato una nuova lista,
pure ordinata, contenente tutti e soli gli elementi contenuti nelle due liste di ingresso.
La funzione non deve alterare le liste di ingresso; perciò il loro contenuto dovrà
essere copiato in nuovi elementi che comporranno la nuova lista.
Per semplicità si può assumere che sia possibile assegnare direttamente variabili di
tipo TipoElemento (cioè che si possa scrivere a=b, se a e b sono due variabili di tipo
TipoElemento).
Eventuali ulteriori sottoprogrammi ausiliari dovranno essere definiti completamente.
La figura sottostante fornisce un esempio di come deve operare la funzione nel caso
TipoElemento sia int.
Copyright © 2008 - The McGraw-Hill Companies srl
50
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
L1
3
L2
L
10
5
3
5
24
56
10
24
56
Suggerimento per realizzare la versione non ricorsiva della funzione
Si definisca una funzione ausiliaria copia() che riceva come parametro una lista e ne
copi il contenuto in un’altra lista.
La funzione merge() si potrebbe comportare nel modo seguente:
- Se entrambe le liste passate alla funzione sono vuote, si ritorna ovviamente la
lista vuota.
- Se una sola delle due liste è vuota si copia l’altra nella lista risultato e si
ritorna quest’ultima.
- Altrimenti (entrambe le liste non sono vuote):
o Si inizializza la lista risultato con il minore tra i primi elementi delle
due liste.
o Si inizializzano opportuni puntatori correnti sia delle liste di ingresso
che della lista risultato (il puntatore corrente alla lista risultato punta
sempre all’ultimo elemento della lista).
o Indi, finché entrambe le liste di ingresso non sono state percorse
completamente:
Si aggiunge in fondo alla lista risultato (tramite il suo puntatore
corrente) l’elemento minore tra quelli puntati dai puntatori
correnti delle liste di ingresso, avanzando di conseguenza i vari
puntatori.
Copyright © 2008 - The McGraw-Hill Companies srl
51
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
o Quando si è giunti in fondo a una delle due liste si copia la parte
rimanente dell’altra lista in fondo alla lista risultato.
NB. Se si segue il suggerimento, non è indispensabile codificare la procedura
ausiliaria copia(): all’occorrenza è sufficiente dichiararla. Funzioni ausiliare diverse da
copia(), invece, vanno completamente definite.
Soluzione dell’esercizio 10.4
Parte a
struct EL
{
TipoElemento info;
struct EL *next;
};
typedef struct EL TipoElementoLista;
typedef TipoElementoLista *TipoLista;
Parte b (versione non ricorsiva).
TipoLista merge (TipoLista lista1, TipoLista lista2)
{
TipoLista curr1, curr2, curr, temp, lista_unione;
/*prototipo procedura ausiliaria che copia in lista2 il contenuto di lista1*/
void copia(TipoLista lista1, TipoLista *lista2);
lista_unione = NULL;
curr1 = lista1;
curr2 = lista2;
if (curr1 == NULL && curr2 == NULL)
return lista_unione;
else if (curr1 == NULL)
copia(lista2, &lista_unione);
else if (curr2 == NULL)
copia(lista1, &lista_unione);
else
{
lista_unione = malloc(sizeof(TipoElementoLista));
lista_unione->next = NULL;
curr = lista_unione;
if (precede(curr1->info, curr2->info))
{
lista_unione->info = curr1->info;
curr1 = curr1->next;
}
else
{
lista_unione ->info = curr2->info;
curr2 = curr2->next};
}
while (curr1 != NULL && curr2 != NULL)
{
temp = malloc(sizeof(TipoElementoLista));
temp->next = NULL;
curr->next = temp;
curr = temp;
if (precede(curr1->info, curr2->info))
Copyright © 2008 - The McGraw-Hill Companies srl
52
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
{
temp->info = curr1->info;
curr1 = curr1->next;
}
else
{
temp->info = curr2->info;
curr2 = curr2->next;
}
}
if (curr1 == NULL)
copia(curr2, curr -> next);
else
copia(curr1, curr -> next);
return lista_unione;
}
}
void copia(TipoLista lista1, TipoLista *lista2)
{
TipoLista temp, curr1, curr2;
*lista2 = NULL;
curr1 = lista1;
if (curr1 != NULL)
{
temp = malloc(sizeof(TipoElementoLista));
temp->next = NULL;
temp->info = curr1-> info;
*lista2 = temp; curr2 = temp; curr1 = curr1->next;
}
while (curr1 != NULL)
{
temp = malloc(sizeof(TipoElementoLista));
temp->next = NULL;
temp->info = curr1->info;
curr2->next = temp; curr2 = temp; curr1 = curr1->next;
}
}
Punto b (versione ricorsiva).
TipoLista merge (TipoLista lista1, TipoLista lista2)
{
TipoLista lista_unione;
if (lista1 == NULL && lista2 == NULL)
return NULL;
if (lista1 == NULL)
{
lista_unione = malloc(sizeof(TipoElementoLista));
lista_unione -> info = lista2->info;
lista_unione->next = merge(lista1, lista2->next);
}
else if (lista2 == NULL)
{
lista_unione = malloc(sizeof(TipoElementoLista));
lista_unione -> info = lista1->info;
Copyright © 2008 - The McGraw-Hill Companies srl
53
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
lista_unione->next = merge(lista1->next, lista2);
}
else
{
lista_unione = malloc(sizeof(TipoElementoLista));
if (precede(lista1->info, lista2->info))
{
lista_unione -> info = lista1->info;
lista_unione->next = merge(lista1->next, lista2);
}
else
{
lista_unione -> info = lista2->info;
lista_unione->next = merge(lista1, lista2->next);
}
}
return lista_unione;
}
Esercizio 10.5,
Punto a.
Si consideri il seguente programma:
#include <stdio.h>
#include <stdlib.h>
main ()
{
int **P; int *Q;
Q = malloc(sizeof(int));
P = &Q;
**P = 5;
*Q = 4;
printf(“il valore finale di **P è %d \n”, **P);
}
Si dica, spiegandone brevemente le ragioni, quale sarà l’output del programma.
Punto b.
Si risolva lo stesso esercizio per la seguente variazione del programma precedente:
#include <stdio.h>
#include <stdlib.h>
typedef int *Pint;
main ()
{
int **P; int *Q; int x;
x = 27;
Q = malloc(sizeof(int));
P = malloc(sizeof(Pint));
*P = Q;
**P = 4;
Q = &x;
P = &Q;
*Q = 5;
Copyright © 2008 - The McGraw-Hill Companies srl
54
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
printf(“il valore finale di **P è %d e quello di x è %d \n”, **P, x);
}
Soluzione dell’Esercizo 10.5
Punto a.
Dopo la malloc e l’assegnazione P = &Q in memoria si crea una situazione come
indicato in figura:
P
Q
**P = 5 produce la situazione successiva seguente:
P
Q
5
*Q = 4 però riscrive il valore 4 nella stessa cella dove era stato scritto 5. Perciò il
risultato finale è l’output seguente:
il valore finale di **P è 4
Punto b.
Dopo l’esecuzione delle istruzioni:
x = 27;
Q = malloc(sizeof(int));
P = malloc(sizeof( Pint));
*P = Q;
si è creata la situazione seguente:
P
Q
x
27
Copyright © 2008 - The McGraw-Hill Companies srl
55
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Assegnando a Q l’indirizzo di x e a P quello di Q, si ottiene l’effetto che
l’assegnamento *Q = 5 sostituisce 5 a 27 in x. Ma x è anche puntata da **P. Quindi il
risultato finale è l’output seguente:
il valore finale di **P è 5 e quello di x è 5
Copyright © 2008 - The McGraw-Hill Companies srl
56
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Capitolo 14
Archivi e basi di dati
Esercizi SQL, Data Definition Language e Data Manipulation Language.
Esercizio 14.1
Siano date le seguenti relazioni:
persona (cod_fiscale, nome, eta, sesso)
automobile (targa, proprietario, colore)
Definire lo schema relazionale tramite il DDL SQL.
Soluzione dell’esercizio 14.1
CREATE TABLE persona
(
cod_fiscale: char(9), PRIMARY KEY, NOT NULL,
nome: char(20),
eta: integer,
sesso: char(1)
)
CREATE TABLE automobile
(
targa(9), PRIMARY KEY, NOT NULL,
proprietario: char(9),
colore: char(10)
)
Esercizio 14.2
Partendo dalle relazioni definite nell’esercizio precedente e riempite con i dati
seguenti:
Relazione: persona
nome
cod_fiscale
Rossi
RSS123456
Bianchi BIA654321
Verdi
VER441611
Grandi GRA741852
eta
25
29
26
50
sesso
M
M
F
F
Relazione: automobile
proprietario
targa
RSS123456
AG125FA
VER441611
FF111GG
GRA741852
XX222FF
RSS123456
FA143XX
BIA654321
GA766AG
colore
rosso
azzurro
rosso
giallo
rosso
Definire, usando il DML SQL, le seguenti interrogazioni:
a. Estrarre il nome e l’età di tutte le persone di sesso femminile.
b. Estrarre le targhe di tutte le automobili i cui proprietari hanno meno di 30
anni.
c. Estrarre i nomi di tutte le persone di sesso maschile proprietarie di
automobili rosse.
Per ognuna di esse si disegni inoltre la tabella contenente i risultati
dell’interrogazione.
Copyright © 2008 - The McGraw-Hill Companies srl
57
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Soluzione dell’esercizio 14.1
SELECT nome, eta
FROM persona
WHERE persona.sesso = 'F’
nome
Verdi
Grandi
eta
26
50
SELECT targa
FROM persona, automobile
WHERE persona.cod_fiscale = automobile.proprietario And persona.eta < 30
targa
AG125FA
FA143XX
GA766AG
FF111GG
SELECT nome
FROM persona, automobile
WHERE persona.cod_fiscale = automobile.proprietario And persona.sesso='M'
And automobile.colore = 'rosso'
nome
Rossi
Bianchi
Copyright © 2008 - The McGraw-Hill Companies srl
58
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Capitolo 18
La visione dei sistemi informatici da parte dell’utente finale
Esercizi EXCEL.
Esercizio 18.1
Si costruisca un archivio, usando un qualsiasi foglio elettronico, contenente
informazioni relative a un insieme di dipendenti di un'azienda. Tali informazioni
devono contenere, tra l'altro:
- Nome e cognome della persona
- Data di nascita
- Data di assunzione
- Retribuzione annua lorda
Altre informazioni possono essere inserite a discrezione dello studente.
Un ulteriore campo, il cui valore deve essere opportunamente calcolato sulla base
delle informazioni precedenti, deve indicare l'ammontare annuo della pensione cui il
soggetto ha eventualmente diritto, sulla base della seguente definizione:
Se il soggetto ha maturato un'anzianità di servizio ≥ 35 anni (per semplicità si può
calcolare tale anzianità assumendo che l'anzianità di servizio sia il periodo di tempo
intercorso dalla data di assunzione alla data attuale) e < 45 anni la pensione cui ha
diritto è il 60% della retribuzione annua lorda. Se il soggetto ha maturato un'anzianità
di servizio ≥ 45 anni la pensione cui ha diritto è il 90% della retribuzione annua lorda
(la pensione non spetta a chi ha un'anzianità inferiore a 35 anni).
Soluzione dell’esercizio 18.1
Un foglio Excel contenente una possibile soluzione è fornito nel file:
6429-8_18.1.xls.
Per la sua costruzione si è fatto uso
• della funzione Now per indicare la data attuale;
• delle funzioni logiche IF e AND per distinguere in vari casi possibili;
• della funzione differenza per calcolare la differenza tra la data attuale e la data
di assunzione: tale differenza è prodotta in giorni ed è stata quindi divisa per
360 secondo la convenzione commerciale che considera un anno costituito da
12 mesi di 30 giorni l’uno.
Esercizio 18.2
Si risolva l'esercizio 7.5 utilizzando un foglio elettronico. In tal caso i dati di ingresso
e di uscita devono trovarsi in apposite posizioni del foglio elettronico.
Soluzione dell’esercizio 18.2
Un foglio Excel contenente una possibile soluzione è fornito nel file:
6429-8_18.2.xls.
A mo’ di esempio una colonna contiene il calcolo della prima funzione richiesta e
un’altra il calcolo della seconda.
Copyright © 2008 - The McGraw-Hill Companies srl
59
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizio 18.3
Si costruisca un archivio per la gestione (semplificata) di un registro IVA:
- nella prima colonna si trova il numero progressivo attribuito al documento di
spesa;
- nella seconda colonna si trovano gli estremi del fornitore;
- nella terza l'imponibile ad aliquota 10%;
- nella quarta l'imposta relativa all'imponibile indicato in precedenza (cioè il
10% di quanto indicato nella terza colonna)
- nella quarta e quinta rispettivamente si trovano imponibile e imposta relativi
all'aliquota 20%;
- nella sesta colonna si trova il totale dell'operazione (si noti che alcune fatture
possono avere imponibili e imposte per entrambe le aliquote).
La riga in fondo al foglio contiene i totali come suggerito dalla figura sottostante.
Registro IVA
Numero
progressivo
Dati del
cliente
Imponibile
al 10%
Imposta al
10%
Imponibile
al 20%
Imposta al
20%
Totale
1
Telecom,
....
AEM, .....
Officina
Pinco
10.000
1.000
234.560
46.912
292.472
200.000
20.000
1.000.000
200.000
220.000
1.200.000
Zzz
vvvv
tttt
2
3
....
Totali
xxx
yyyy
Un foglio Excel contenente una possibile soluzione è fornito nel file:
6429-8_18.3.xls.
Esercizio 18.4
Il signor Rossi vuole tenere sotto controllo i propri conti mensilmente. All’uopo egli
desidera registrare ogni mese entrate e uscite, divise in opportune categorie, in modo
da sapere se e quanto ha guadagnato o perso; inoltre egli desidera tenere sotto
controllo anche il proprio conto corrente bancario, tenendo traccia di tutte le
operazioni di prelievo-deposito effettuate in modo da poter sapere in ogni momento di
quanto denaro egli dispone.
Si costruisca mediante Framework uno strumento che soddisfi le esigenze del signor
Rossi.
Parte Facoltativa
Si osservi che solitamente pagamenti (e incassi) possono avvenire sia in contanti che
mediante operazioni bancarie (bonifici, assegni, ...). Ad esempio: lo stipendio
potrebbe essere accreditato automaticamente dal datore di lavoro sul cc del signor
Rossi. Alcune spese egli potrebbe effettuarle pagando in assegni, ma altre usando
contante che egli preleva ogni tanto dalla banca. In questo modo le operazioni sul cc
non coincidono necessariamente con le operazioni di entrata-uscita.
Copyright © 2008 - The McGraw-Hill Companies srl
60
Informatica: Arte e Mestiere, Terza edizione
Esercizi
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Si organizzi allora lo strumento in modo che incassi e pagamenti effettuati tramite
operazioni bancarie possano essere registrati dal signor Rossi una sola volta (ad
esempio se egli paga un elettrodomestico mediante un assegno egli segna questa spesa
una sola volte mediante il suo strumento che provvede automaticamente ad aggiornare
sia il conto ricavi-spese che lo stato del cc bancario). Le operazioni effettuate in
contante invece devono essere trattate separatamente: ad esempio se il giorno 10 il
signor Rossi preleva L. 500,000 questa operazione comporta un aggiornamento del
cc.ma nessuna spesa nel conto entrate-uscite; successivamente egli spende L. 250,000
al ristorante e L. 250,000 in abbigliamento pagando entrambe le volte in contanti:
entrambe le operazioni vanno allora registrate come uscite nel registro entrate-uscite,
ma non comportano alcun aggiornamento sul cc; chiaramente alla fine del mese I
conti devono “tornare”, cioè la variazione dell’ammontare dell cc (+ la variazione
dell’ammontare del contante disponibile in cassa) deve uguagliare il netto del conto
entrate-uscite.
Soluzione dell’esercizio 18.4
Una possibile soluzione della versione facoltativa è impostata nei fogli Excel forniti
nel file: 6429-8_18.4.xls.
Si noti che sono stati usati due fogli nello stesso file: uno per gestire il conto entrateuscite, chiamto ContoEc, l’altro, Banca, per gestire il conto corrente bancario. Alcune
celle del foglio Banca sono calcolate automaticamente sulla base delle operazioni
registrate nel ContoEc: queste sono suddivise, per ogni voce, in operazioni in contanti
e operazioni effettuate tramite banca. Queste ultime sono automaticamente riportate
nel foglio Banca. L’utente deve invece riportare sul foglio Banca tutte le operazioni di
prelievo-deposito contanti. Si noti che, se a fine di un periodo il signor Rossi ha nel
portafoglio (ammontare complessivo dei contanti) la stessa cifra che aveva all’inizio
del periodo, il margine complessivo del periodo risultante nel ContoEc eguaglia la
differenza tra fine-periodo e inizio-periodo del foglio Banca.
NB. Per semplicità i fogli del file sono stati riempiti solo relativamente al mese di
gennaio.
Esercizio 18.5
Si vuole ripartire la spesa di costruzione di una strada a fondo chiuso sulla quale
insistono quattro condomini di nome Primula, Violetta, Fiordaliso e Gelsomino,
composti rispettivamente da 8, 6, 12 e 4 appartamenti e che distano dall’inizio della
strada rispettivamente 10, 100, 250 e 300 metri. La spesa, di complessive L
50.000.000, va ripartita in base al numero di appartamenti di ogni condominio, pesato
con la sua distanza dall’inizio della strada. Si costruisca un foglio elettronico che,
tramite l’introduzione dei dati del problema, permetta di ottenere una ripartizione
della spesa in modo analogo a quanto mostrato nella seguente tabella.
Condominio
Primula
Violetta
Fiordaliso
Gelsomino
D=distanza
N=no.app.ti
10
100
250
300
Quote Q = N x D
8
6
12
4
80
600
3000
1200
4880
Totali
Costo quota C = Costo complessivo/no. quote =
Ripartizione = Q x C
819672
6147541
30737705
12295082
50000000
10245,90164
Copyright © 2008 - The McGraw-Hill Companies srl
61
Informatica: Arte e Mestiere, Terza edizione
Stefano Ceri, Dino Mandrioli, Licia Sbattella
Esercizi
Soluzione omessa in quanto derivabile immediatamente dalla figura esplicativa.
Copyright © 2008 - The McGraw-Hill Companies srl
62
Scarica

Esercizi su web per il testo Informatica: Arte e mestiere