Esercitazione 6: Gestione file e ricorsione

Esercitazione n. 6
Gestione dei file
e
ricorsione
dott. Carlo Todeschini – [email protected] – Politecnico di Milano – A.A. 2010/2011
Queste slide sono distribuite con licenza Creative Commons
Attribuzione-Non commerciale-Condividi allo stesso modo 2.5 Italia
Problema: Che cosa succede se... (es. errori_array.c)
#include <stdio.h>
#define MAX_D 10
int j = 1;
void pr_fun (int a[])
{
int i=0;
for (i=0 ; i<MAX_D+2 ; i++)
a[i] = i*j;
j++;
}
void pr (int a[MAX_D])
{
int i=0;
for (i=0 ; i<MAX_D+2 ; i++)
printf ("%d ", a[i]);
}
main ()
{
int b[MAX_D];
pr_fun (b);
pr (b);
printf ("\n\n");
pr_fun (b);
pr (b);
printf ("\n");
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
2
Problema: Che cosa succede se... (es. errori_array.c)
tode@benfuter:~/esempi$ gcc -o
es_01_prova_con_array es_01_prova_con_array.c
tode@benfuter:~/esempi$ ./es_01_prova_con_array
0 1 2 3 4 5 6 7 8 9 10 11
0 2 4 6 8 10 12 14 16 18 20 22
Segmentation fault
tode@benfuter:~/esempi$
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
3
Gestione dei file: ripasso/1...
Per accedere a un file (sequenza lineare di byte) è necessario
definire una variabile che punti al file:
FILE *fp;
Nota: si utilizza la libreria standard “stdio.h”.
“fp” è definito un file pointer
E' possibile gestire un file in tre fasi:
apertura
gestione/modifica
chiusura
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
4
Gestione dei file: ripasso/1...
Apertura di un flusso di comunicazione:
FILE *fopen (nomefile, modalità)
modalità: r, w, a, rb, wb, ab, r+, w+, a+, rb+, wb+, ab+
“r”:
“w”:
“r+”:
“w+”:
“a”:
“a+”:
sola lettura
sola scrittura
lettura e scrittura
scrittura e lettura
append
lettura e append
(errore se non esiste)
(creazione se non esiste)
(errore se non esiste)
(creazione se non esiste)
Chiusura di un flusso di comunicazione
int fclose (FILE *fp)
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
5
Gestione dei file: ripasso/2...
Verifica se nelle precedenti operazioni di lettura/scrittura è stato
riscontrato un errore:
int ferror (FILE *fp)
Nota: se restituisce 0 non ci sono stati errori
Controlla se è stata raggiunta la fine del file:
int feof (FILE *fp)
Nota: se restituisce 0 non è stata ancora raggiunta la fine
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
6
Gestione dei file: ripasso/3...
Per eseguire una operazione di scrittura formattata:
int fprintf (FILE *fp, stringa di controllo,
elementi)
Per eseguire una operazione di lettura formattata:
int fscanf (FILE *fp, stringa di controllo,
indirizzo elementi)
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
7
Gestione dei file: ripasso/4...
Per eseguire una operazione di lettura di un carattere:
int fgetc (FILE *fp)
Per eseguire una operazione di scrittura di un carattere:
int fputc (int c, FILE *fp)
Per eseguire una operazione di lettura di una stringa:
char *fgets (char *s, int n, FILE *fp)
Per eseguire una operazione di scrittura di una stringa:
int fputs (char *s, FILE *fp)
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
8
Gestione dei file: ripasso/5...
Per eseguire una operazione di lettura di uno o più blocchi di dati:
int fread (void *ptr, dim_elemento,
num_elementi, FILE *fp)
Per eseguire una operazione di scrittura di uno o più blocchi di dati:
int fwrite (void *ptr, dim_elemento,
num_elementi, FILE *fp)
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
9
Gestione dei file: ripasso/6...
Per eseguire un accesso diretto a un file che sposta l'indicatore di
posizione di un numero “offset” di byte, in base alla direzione
stabilita da “ref_point”:
int fseek (FILE *fp, long offset,
int ref_point)
Per recuperare il valore corrente dell'indicatore di posizione del
file:
int ftell (FILE *fp)
Per riportare all'inizio del file l'indicatore di posizione:
rewind (FILE *fp)
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
10
Attenzione: formato dei file...
Tipi di file:
➢
Testo
...
➢
Binari
...
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
11
C/1: Merge di file – Problema
Si vuole realizzare un programma in linguaggio C in grado di:
➢
➢
leggere due file che contengono rispettivamente il titolo e gli attori
principali (anche più di uno) di una serie di film
creare un file unico con, per ogni film, titolo e attori principali.
Formato file “titoli”:
Formato file “attori”:
Il Signore degli Anelli
Guerre stellari
Frankenstein Jr.
Viggo Mortensen
Ian McKellen
Elijah Wood
#
Mark Hamill
Harrison Ford
#
Marty Feldman
Gene Wilder
#
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
12
C/1: Merge di file – Codice sorgente/1
/* Questo file contiene la definizione di una funzione,
'mergeBiblioData', che prende in input il nome di
due file che contengono rispettivamente il titolo e
gli attori principali (anche più di uno) di una serie
di film, e creano un file unico con, per ogni film,
titolo e attori principali.
Nel file con i titoli, ad ogni riga corrisponde un
film diverso (non ci devono essere righe vuote alla
fine).
Nel file con gli attori, le sequenze di attori sono
separate da una riga che contiene il solo carattere
'#' (non sono ammesse righe vuote alla fine).
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
13
C/1: Merge di file – Codice sorgente/2
Per esempio un file di attori può essere:
Viggo Mortensen
Ian McKellen
Elijah Wood
#
Mark Hamill
Harrison Ford
#
Marty Feldman
Gene Wilder
#
*/
La funzione 'mergeBiblioData' ritorna un valore intero,
che può assumere diversi valori a seconda del risultato
della funzione:
- 0 la funzione ha avuto successo
- 1 non è stato possibile aprire il file di input
con i titoli dei film
- 2 non è stato possibile aprire il file di input con
gli attori
- 3 non è stato possibile aprire il file di destinazione
- 4 il formato dei file di input non è corretto (per
esempio se i due file contengono dati di un numero
diverso di film)
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
14
C/1: Merge di file – Codice sorgente/3
#include <stdio.h>
#include <string.h>
#include "userTypes.h"
/* Si definisce il significato del codice ritornato
dalla funzione 'mergeBiblioData' */
#define SUCCESSO 0
#define FILE_TITOLI_NON_APERTO 1
#define FILE_ATTORI_NON_APERTO 2
#define OUTPUT_NON_APERTO 3
#define FORMATO_FILE_INPUT_ERRATO 4
/* Al massimo i file di input possono avere linee
lunghe MAX_LUNGH_LINEA elementi */
#define MAX_LUNGH_LINEA 80
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
15
C/1: Merge di file – Codice sorgente/4
/* Il tipo corrispondente di stringa ha 2 caratteri in
più: uno per il carattere '\000' di fine stringa, e
uno per il carattere di 'a capo' ('\n') */
typedef char riga_input [MAX_LUNGH_LINEA+2];
int mergeBiblioData (char *nome_file_titoli,
char *nome_file_attori,
char *nome_file_output)
{
FILE *titoli, *attori, *output;
riga_input titolo, attore;
bool prossimo_titolo;
int lstr;
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
16
C/1: Merge di file – Codice sorgente/5
/* Si aprono i file di input in modalità "sola lettura,
file di testo"; se l'operazione di apertura del file
non ha successo si ritorna un errore */
titoli = fopen (nome_file_titoli, "r");
if (titoli == NULL)
return FILE_TITOLI_NON_APERTO;
/* Nel caso si ritorni un errore, ci si deve prima
ricordare di chiudere il file precedentemente aperto
(stessa cosa quando si cerca di aprire il file di
output) */
attori = fopen (nome_file_attori, "r");
if (attori == NULL)
{
fclose (titoli);
return FILE_ATTORI_NON_APERTO;
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
17
C/1: Merge di file – Codice sorgente/6
/* Si apre il file di output in modalità "scrittura,
file di testo"; se l'operazione di apertura del
file non ha successo si ritorna un errore */
output = fopen (nome_file_output, "w");
if (output == NULL)
{
fclose (attori);
fclose (titoli);
return OUTPUT_NON_APERTO;
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
18
C/1: Merge di file – Codice sorgente/7
while (!feof(titoli))
{
/* Se non si è ancora arrivati in fondo al file dei
titoli, ma non ci sono più attori, si segnala un
errore, perchè ci sono più titoli che gruppi di
attori */
if (feof (attori))
{
fclose (titoli);
fclose (attori);
fclose (output);
return FORMATO_FILE_INPUT_ERRATO;
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
19
C/1: Merge di file – Codice sorgente/8
fgets (titolo, MAX_LUNGH_LINEA+1, titoli);
/* Si controlla l'ultimo carattere inserito nella
stringa: se non è 'newline', si inserisce il
carattere di '\n' in fondo alla stringa */
lstr = strlen (titolo);
if (titolo[lstr-1] != '\n')
{
titolo[lstr] = '\n';
titolo[lstr+1] = '\000';
}
/* Si scrive il titolo ('newline' compreso!) nel file
di output */
fputs (titolo, output);
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
20
C/1: Merge di file – Codice sorgente/9
/* Si recuperano i nomi degli attori; se non ci sono
più attori nel file vuol dire che ci sono più
titoli di gruppi di attori, e si segnala un
errore */
prossimo_titolo = false;
while (!feof(attori) && !prossimo_titolo)
{
fgets (attore, MAX_LUNGH_LINEA+1, attori);
/* Se il primo carattere della riga è '#' si passa
al prossimo titolo, cioè sono finiti gli attori
per il film corrente */
if (attore[0] == '#')
{
prossimo_titolo = true;
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
21
C/1: Merge di file – Codice sorgente/10
else
{
/* Se serve, si aggiunge un '\n' in fondo alla
riga letta */
lstr = strlen (attore);
if (attore[lstr-1] != '\n')
{
attore[lstr] = '\n';
attore[lstr+1] = '\000';
}
}
}
fputs (attore, output);
}
fprintf (output, "#\n");
fclose (titoli);
fclose (output);
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
22
C/1: Merge di file – Codice sorgente/11
/* Se si è giunti in fondo al file dei titoli, ma ci
sono ancora attori, si segnala un errore, perchè
ci sono più gruppi di attori che titoli di film */
if (!feof(attori))
{
fclose (attori);
return FORMATO_FILE_INPUT_ERRATO;
}
}
fclose (attori);
return SUCCESSO;
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
23
C/1: Merge di file – Codice sorgente/12
main ()
{
int ris;
ris = mergeBiblioData ("es_02_mergeFile_titoliFilm",
"es_02_mergeFile_attoriFilm",
"es_02_mergeFile_datiFilm");
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
24
C/1: Merge di file – Codice sorgente/13
}
switch (ris)
{
case SUCCESSO:
printf ("Operazione avvenuta con successo\n");
break;
case FILE_TITOLI_NON_APERTO:
printf ("Errore nell'apertura del file con i titoli\n");
break;
case FILE_ATTORI_NON_APERTO:
printf ("Errore nell'apertura del file con gli attori\n");
break;
case OUTPUT_NON_APERTO:
printf ("Errore nell'apertura del file di output\n");
break;
case FORMATO_FILE_INPUT_ERRATO:
printf ("I file di input hanno un formato errato\n");
break;
default:
printf ("Codice ritornato non riconosciuto!\n");
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
25
C/2: Controllo parentesi – Problema
Si vuole realizzare un programma in linguaggio C in grado di leggere
un file di testo in codice C, e di controllare che per ogni parentesi
graffa e tonda aperta ce ne sia una chiusa corrispondente (vengono
verificate anche le parentesi all'interno dei commenti).
Una parentesi graffa non può apparire mentre ci sono parentesi tonde
aperte.
Esercizio da svolgere in autonomia: modificare il
programma in modo tale che le parentesi all'interno dei
commenti vengano saltate (per questo occorre riconoscere le
sequenze di caratteri che marcano l'inizio e la fine di un
commento...)
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
26
C/2: Controllo parentesi – Codice sorgente/1
/* Questo file contiene la definizione di una funzione,
'controllaParentesi', che prende in input il nome di
un file che contiene codice C, e controlla che per ogni
parentesi graffa e tonda aperta ce ne sia una chiusa
corrispondente (vengono verificate anche le parentesi
all'interno dei commenti). Una parentesi graffa non può
apparire mentre ci sono parentesi tonde aperte.
La funzione ritorna un intero, che può assumere i
seguenti significati:
- 0 tutto OK
- 1 sono presenti delle parentesi graffe aperte
- 2 sono presenti delle parentesi tonde aperte
- 3 sono presenti delle parentesi graffe chiuse e
mai aperte
- 4 sono presenti delle parentesi tonde chiuse e
mai aperte
- 5 sono presenti graffe aperte o chiuse ma ci sono
ancora delle tonde da chiudere
- 6 impossibile aprire il file
*/
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
27
C/2: Controllo parentesi – Codice sorgente/2
#include <stdio.h>
#define
#define
#define
#define
#define
#define
#define
OK 0
GRAFFE_APERTE 1
TONDE_APERTE 2
GRAFFE_NON_APERTE 3
TONDE_NON_APERTE 4
GRAFFE_CON_TONDE 5
FILE_NON_APERTO 6
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
28
C/2: Controllo parentesi – Codice sorgente/3
int controllaParentesi (char *nome_file_C)
{
FILE *file;
char curr;
int graffe_aperte = 0,
tonde_aperte = 0,
ris = OK;
/* Si apre il file di input in modalità sola lettura,
file di testo; se l'operazione di apertura del file
non ha successo si ritorna un errore.
*/
file = fopen (nome_file_C, "r");
if (file == NULL)
return FILE_NON_APERTO;
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
29
C/2: Controllo parentesi – Codice sorgente/4
while (ris == OK && !feof(file))
{
curr = fgetc (file);
if (curr == '{')
{
if (tonde_aperte > 0)
ris = GRAFFE_CON_TONDE;
else
graffe_aperte++;
}
else if (curr == '(')
tonde_aperte++;
else if (curr == '}')
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
30
C/2: Controllo parentesi – Codice sorgente/5
{
}
if (graffe_aperte > 0)
{
if (tonde_aperte > 0)
{
ris = GRAFFE_CON_TONDE;
}
else
{
graffe_aperte--;
}
}
else
ris = GRAFFE_NON_APERTE;
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
31
C/2: Controllo parentesi – Codice sorgente/6
}
else if (curr == ')')
{
if (tonde_aperte > 0)
tonde_aperte--;
else
ris = TONDE_NON_APERTE;
}
if (ris
ris =
else if
ris =
}
== OK && graffe_aperte > 0)
GRAFFE_APERTE;
(ris == OK && tonde_aperte > 0)
TONDE_APERTE;
fclose (file);
return ris;
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
32
C/2: Controllo parentesi – Codice sorgente/7
main ()
{
int ris;
ris = controllaParentesi
("es_03_controlloParentesiTest.c");
switch (ris)
{
case OK:
printf ("Operazione avvenuta con successo\n");
break;
case GRAFFE_APERTE:
printf ("Ci sono delle parentesi graffe aperte\n");
break;
case TONDE_APERTE:
printf ("Ci sono delle parentesi tonde aperte\n");
break;
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
33
C/2: Controllo parentesi – Codice sorgente/8
}
case GRAFFE_NON_APERTE:
printf ("Ci sono delle parentesi graffe chiuse e
mai aperte\n");
break;
case TONDE_NON_APERTE:
printf ("Ci sono delle parentesi tonde chiuse e
mai aperte\n");
break;
case GRAFFE_CON_TONDE:
printf ("Ci sono delle parentesi graffe aperte o
chiuse con parentesi tonde da chiudere\n");
break;
case FILE_NON_APERTO:
printf ("Non è stato possibile aprire il file\n");
break;
default:
printf ("Codice ritornato incomprensibile!\n");
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
34
Programmazione ricorsiva: ripasso/1...
Dal libro di testo:
“Si parte dal presupposto che per moltissimi problemi
la soluzione per un caso generico può essere ricavata
sulla base della soluzione di un altro caso,
generalmente più semplice, dello stesso problema”
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
35
Programmazione ricorsiva: ripasso/2...
Un sottoprogramma può dunque richiamare se stesso!
String reversal
Il classico esempio: la successione dei numeri di Fibonacci
f0 = 0
f1 = 1
Per n>1, fn = fn-1 + fn-2
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
36
Programmazione ricorsiva: ripasso/3...
#include <stdio.h>
int calcolaFibonacci (int numero);
main ()
{
int numeroDaCalcolare;
printf ("Inserire numero: ");
scanf ("%d", &numeroDaCalcolare);
printf ("Numero di Fibonacci f(%d) = %d\n",
numeroDaCalcolare, calcolaFibonacci (numeroDaCalcolare));
}
int calcolaFibonacci (int numero)
{
if (numero == 0)
return 0;
else if (numero == 1)
return 1;
else
return (calcolaFibonacci (numero-1) +
calcolaFibonacci (numero-2));
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
37
C/4: Palindrome – Problema
Si vuole realizzare un programma in linguaggio C in grado di
verificare se una parola inserita dall'utente è o meno
palindroma.
“Il palindromo è una serie di simboli leggibile, senza
cambiamento di significato, in ordine invertito.”
Es:
ama
anna
effe
ereggere
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
38
C/4: Palindrome – Codice sorgente/1
/* Questo programma prende una stringa e determina se
è palindroma, cioè se è uguale sia che la si legga
a partire dall'inizio, sia che la si legga a
partire dal fondo.
Per esempio, la parola RADAR è palindroma.
Per verificare se una stringa è palindroma si usa
tipicamente un algoritmo ricorsivo, che funziona
nel modo che segue:
1. se la stringa da verificare è di lunghezza 1 o 0,
STOP: è palindroma
2. confrontare il primo carattere con l'ultimo nella
stringa: se sono diversi STOP, la stringa NON E'
palindroma
3. se il primo e l'ultimo carattere sono uguali,
ripetere l'algoritmo sulla stringa ottenuta
eliminando il primo e l'ultimo carattere
*/
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
39
C/4: Palindrome – Codice sorgente/2
#include <stdio.h>
#include <string.h>
#include "userTypes.h"
#define MAX_EL 100
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
40
C/4: Palindrome – Codice sorgente/3
bool palindroma (char *s, int n_el)
{
/* Caso di base: se la stringa ha solo 1 elemento o se
è la stringa vuota, è palindroma */
if (n_el < 2)
{
return true;
}
}
/* Passo ricorsivo */
if (s[0] == s[n_el-1])
{
return palindroma(s+1, n_el-2);
}
else
{
return false;
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
41
C/4: Palindrome – Codice sorgente/4
main ()
{
char parola[MAX_EL+1];
bool palindroma (char *s, int n_el);
}
printf ("Inserire la parola da controllare: ");
scanf ("%s", parola);
if (palindroma (parola, strlen(parola)))
{
printf ("La parola \"%s\" è palindroma\n", parola);
}
else
{
printf ("La parola \"%s\" NON è palindroma\n",
parola);
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
42
C/4: Palindrome – Compito
Il programma realizzato è in grado di riconoscere solo parole
palindrome come ad esempio “ama”, “anna”, “effe”,
“ereggere”.
Da svolgere autonomamente:
Modificare tale programma in modo che sia in grado leggere
frasi palindrome come ad esempio “Alle carte t'alleni nella
tetra cella”, “E' corta e atroce” (nota: non devono essere
considerati segni di punteggiatura, accenti e spazi; cercare in
rete frasi palindrome da verificare...)
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
43
C/5: Binary search – Problema
Si vuole realizzare un programma in linguaggio C che acquisisca
una sequenza di interi, e li inserisca in modo ordinato (in ordine
crescente) in un array di elementi.
Viene data poi la possibilità all'utente di inserire un valore da
cercare nell'array. La ricerca viene fatta con l'algoritmo di ricerca
binaria (quello dell'elenco telefonico...).
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
44
C/5: Binary search – Codice sorgente/1
/* Questo programma prende una sequenza di interi,
e li inserisce in modo ordinato (in ordine
crescente) in un array di elementi.
Viene chiesto all'utente di inserire un valore da
cercare nell'array. La ricerca viene fatta con
l'algoritmo di ricerca binaria (quello dell'elenco
telefonico...).
*/
Gli scopi della funzione definita in questo programma
sono di mostrare come in realtà gli array siano
SEMPRE passati per indirizzo (funzione inser_ord), e
fare un esempio di funzione ricorsiva (binary_search)
#include <stdio.h>
#include "userTypes.h"
#define MAX_EL 100
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
45
C/5: Binary search – Codice sorgente/2
/* la funzione prende un array di interi a (il quale ha
le prime n_el caselle occupate) e inserisce
in modo ordinato un nuovo intero v, se v ancora
non esiste nell'array.
Se l'operazione va a buon fine viene restituito
l'indice in cui viene inserito il nuovo elemento e
il numero di elementi nell'array viene incrementato
di 1, altrimenti viene restituito -1 (una variante
rispetto all'uso di un tipo bool apposito).
Si tratta l'array con la sintassi degli array,
quindi si riferiscono gli elementi con le parentesi
quadre. */
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
46
C/5: Binary search – Codice sorgente/3
int inser_ord (int v, int a[MAX_EL], int *n_el)
{
/* possibile intestazione anche per la funzione:
int inser_ord (int v, int a[], int *n_el)
int inser_ord (int v, int *a, int *n_el)
*/
int j, i=0;
while (i<*n_el && a[i] < v)
{
i++;
}
/* Se il valore esiste già si ritorna -1 senza
modificare l'array */
if (i<*n_el && a[i] == v)
{
return -1;
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
47
C/5: Binary search – Codice sorgente/4
else
{
/* Prima di tutto si spostano tutti gli elementi
nell'array in avanti di un posto */
for (j=*n_el; j>i ; j--)
{
a[j] = a[j-1];
}
a[i] = v;
*n_el = *n_el+1;
/* Attenzione perchè se si scrive *n_el++ non è
corretto perchè viene incrementato l'indirizzo
contenuto in n_el, invece che il contenuto della
cella in cui indirizzo è in n_el */
return i;
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
48
C/5: Binary search – Codice sorgente/5
/* Notare come in realtà in questo programma non si
faccia per niente uso della costante 'MAX_EL'. In
effetti, per il C, scrivere che un parametro in
ingresso è "int a[MAX_EL]", oppure è "int a[]",
oppure ancora (ed è la scrittura più comune) è
"int *a" non cambia niente, le tre scritture sono
del tutto equivalenti.
Non è quindi possibile verificare che l'array passato
sia effettivamente della lunghezza MAX_EL (si potrebbe
tranquillamente chiamare la funzione passando un array
di MAX_EL*2 elementi, e il compilatore non segnalerebbe
nessun errore), ne è possibile verificare che
nell'array ci sia ancora spazio: è la funzione chiamante
che deve preoccuparsi di passare un array che abbia
ancora delle caselle libere per inserire l'elemento
nuovo */
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
49
C/5: Binary search – Codice sorgente/6
/* In questa procedura, che stampa i primi n_el elementi
di un array a di interi, si tratta l'array come un
puntatore (perchè un array in realtà è un puntatore).
Invece di fare riferimento agli elementi con la
notazione con le parentesi quadre, si utilizza la
notazione dei puntatori (con gli '*')
*/
void stampa_array (int *a, int n_el)
{
int i;
for (i=0 ; i<n_el ; i++)
{
printf ("%d ", *(a+i));
}
printf ("\n");
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
50
C/5: Binary search – Codice sorgente/7
/* Questa funzione prende in ingresso un array ordinato di
interi (insieme al numero di caselle occupate dell'array),
e un valore, e ritorna true o false a seconda che il
valore passato sia presente nell'array o no.
L'algoritmo che viene usato è tipicamente ricorsivo:
1. Passo di base: se l'insieme in cui cercare è vuoto
STOP, l'elemento NON esiste;
2. Passo ricorsivo: si prende l'elemento di mezzo
dell'insieme; se l'elemento è uguale a quello cercato
STOP, l'elemento è stato trovato; se l'elemento di
mezzo è MAGGIORE di quello cercato, applicare la
ricerca binaria alla prima metà dell'insieme, altrimenti
applicare la ricerca binaria alla seconda metà
dell'insieme.
*/
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
51
C/5: Binary search – Codice sorgente/8
bool binary_search (int v, int *a, int n_el)
{
/* Caso di base: se l'insieme è vuoto, l'elemento cercato
non esiste */
if (n_el == 0)
{
return false;
}
/* Passo ricorsivo */
if (a[n_el/2] == v)
{
return true;
}
else if (a[n_el/2] > v)
{
return binary_search (v, a, n_el/2);
}
else
{
return binary_search (v, a+n_el/2+1, n_el/2-1+n_el%2);
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
52
C/5: Binary search – Codice sorgente/9
/* La parte più complessa è definire correttamente in C
la forma delle due metà dell'insieme di partenza. Nel
caso in cui si debba applicare la ricerca binaria alla
SECONDA metà dell'insieme di partenza, si deve
passare (ricorsivamente) alla funzione "binary_search"
la seconda metà dell'array a. Per fare questo si passa
l'indirizzo della casella dell'array successiva a
quella che si trova a metà array (inizio della seconda
metà dell'array a), e si specifica che la lunghezza di
questa parte dell'array è n_el/2-1+n_el%2
Infatti, supponendo che n_el sia 8, e quindi che gli
indici delle caselle nell'array a vadano da 0 a 7:
0 1 2 3 4 5 6 7
a[n_el/2] (ovvero l'elemento di indice 4, che è il
quinto) è l'elemento di mezzo che viene confrontato
con v. Se v è maggiore di a[n_el/2] (quindi si trova
nella seconda metà), si effettua la ricerca binaria
sull'insieme [5 6 7], che è in effetti la parte di
array che inizia dall'indice n_el/2+1, ed è lunga
n_el/2-1+n_el%2, cioe' 4-1+0 = 3 */
}
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
53
C/5: Binary search – Codice sorgente/10
main()
{
int dati[MAX_EL], dato_corr;
int num_el=0;
int inser_ord (int v, int a[MAX_EL], int *n_el);
bool binary_search (int v, int *a, int n_el);
void stampa_array (int *a, int n_el);
do
{
printf ("Inserire elemento (0 per terminare, max %d
elementi): ", MAX_EL);
scanf ("%d", &dato_corr);
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
54
C/5: Binary search – Codice sorgente/11
/* Qui si inserisce anche lo 0! */
inser_ord (dato_corr, dati, &num_el);
/* num_el viene passato per indirizzo, viene
incrementato solo se l'elemento non esiste già
nell'array.
*/
Notare come sia possibile non assegnare il valore
ritornato da una funzione, il quale in questo
caso viene ignorato
printf ("Nuova situazione dell'array:\n");
stampa_array (dati, num_el);
} while (dato_corr != 0 && num_el<MAX_EL);
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
55
C/5: Binary search – Codice sorgente/12
do
{
printf ("\nInserire elemento da cercare (0 per
terminare): ");
scanf ("%d", &dato_corr);
if (binary_search (dato_corr, dati, num_el) == true)
{
printf ("\nIl numero %d è presente nell'array\n",
dato_corr);
}
else
{
printf ("\nIl numero %d NON è presente
nell'array\n", dato_corr);
}
} while (dato_corr != 0);
}
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
56
C/compito: La torre di Hanoi – Problema
Si vuole realizzare un programma in linguaggio C in grado di giocare
al gioco della “torre di Hanoi” (v. libro di testo).
Da Wikipedia: “La Torre di Hanoi è un rompicapo matematico
composto da tre paletti e un certo numero di dischi di grandezza
decrescente, che possono essere infilati in uno qualsiasi dei paletti.
Il gioco inizia con tutti i dischi incolonnati su un paletto in ordine
decrescente, in modo da formare un cono. Lo scopo del gioco è
portare tutti dischi sull'ultimo paletto, potendo spostare solo un disco
alla volta e potendo mettere un disco solo su un altro disco più
grande, mai su uno più piccolo.”
Tower of Hanoi
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
57
C/compito: La torre di Hanoi – Buone vacanze
Buon lavoro ;-)
Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – [email protected]
58