Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
PubblicatoPanfilo Ferro Modificato 11 anni fa
1
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Corso di Programmazione 1 a.a.2007/2008 Prof.ssa Chiara Petrioli Corso di Laurea in Informatica Università degli Studi La Sapienza (lezioni 12-15) Puntatori e ricorsione
2
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Aritmetica dei puntatori I puntatori sono degli operandi validi per le espressioni aritmetiche (insieme limitato di operatori aritmetici possono essere applicati a puntatori), le espressioni di assegnamento e le espressioni di confronto – un puntatore potrà essere incrementato e decrementato con gli operatori ++ o --, ad un puntatore potrà essere sommato o sottratto un intero (operatori +, -,-=, +=). Infine ad un puntatore potrà essere sottratto un secondo puntatore. Devono però essere puntatori allo stesso tipo di dato
3
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Aritmetica dei puntatori per operare sui vettori int i; int v[100]; int * vPtr; for (i=0; i<100;i++) v[i]=i;vPtr=&v[0]; 012…9899 v 3000 vPtr vPtr poteva anche essere inizializzato Scrivendo vPtr=v; In quale locazione di memoria si trova v[1]? Ed il generico elemento v[i]?
4
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Operatore sizeof sizeof(nome_di variabile o tipo di dato o costante) È loperatore che consente di determinare quante celle di memoria sono associate ad un certo tipo di dato printf(sizeof(char)=%d\n sizeof(short)=%d\n sizeof(short)=%d\n sizeof(int)=%d\n sizeof(int)=%d\n sizeof(long)=%d\n sizeof(long)=%d\n sizeof(float)=%d\n sizeof(float)=%d\n sizeof(double)=%d\n sizeof(double)=%d\n sizeof(long double)=%d\n, sizeof(long double)=%d\n, sizeof(char),sizeof(short),sizeof(int),sizeof(long), sizeof(char),sizeof(short),sizeof(int),sizeof(long), sizeof(long),sizeof(float),sizeof(double), sizeof(long),sizeof(float),sizeof(double), sizeof(long double)); sizeof(long double)); sizeof(char)=1 sizeof(short)=2 sizeof(int)=2 sizeof(long)=4 sizeof(float)=4 sizeof(double)=8 sizeof(long double)=10
5
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Aritmetica dei puntatori per operare sui vettori int i; int v[100]; for (i=0; i<100;i++) v[i]=i;vPtr=&v[0]; 012…9899 v 3000 vPtr Supponendo che il numero di celle associate ad un Intero sia 2… vPtr+=2 fa puntare vPtr a v[2] 3004
6
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Aritmetica dei puntatori per operare sui vettori int i; int v[100]; for (i=0; i<100;i++) v[i]=i;vPtr=&v[0]; 012…9899 v 3000 3004 vPtr Supponendo che il numero di celle associate ad un Intero sia 2… vPtr-- fa puntare vPtr alla posizione precedente del vettore, v[1] (stessa cosa scrivendo vPtr-=1) Infatti in questo caso la variabile puntatore viene decrementata di una quantità di celle pari a quelle che servono per memorizzare il tipo di dato in modo da far puntare allelemento precedente del vettore 3002
7
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Aritmetica dei puntatori per operare sui vettori int i; int v[100]; int *vPtr; int *vPtr2; for (i=0; i<100;i++) v[i]=i;vPtr=&v[0];vPtr2=&v[99]; 012…9899 v 3000 vPtr Supponendo che il numero di celle associate ad un Intero sia 2… x=vPtr2-vPtr; Assegna ad x il numero di elementi del vettore compresi tra lelemento puntato da vPtr2 e vPtr (infatti il valore delle differenza viene normalizzato al numero di celle necessarie per contenere un intero) in questo caso 99 3198 vPtr2 Laritmetica dei puntatori ha senso con gli elementi di un vettore altrimenti Non si può assumere che variabili dello stesso tipo siano immagazzinate in celle consecutive di memoria Un confronto tra puntatori ha senso solo per puntatori che puntano ad elementi diversi dello stesso vettore e può ad esempio essere usato per controllare quale dei due elementi puntati ha Indice maggiore
8
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Puntatori e vettori 012…9899 v 3000 vPtr v==&v[0] Se vPtr==v v[4] e *(vPtr+4) sono due notazioni equivalenti per far riferimento al valore del quinto elemento del vettore notazione con puntatore e offset Attenzione: il nome del vettore è un puntatore costante punterà sempre alla Prima posizione del vettore, non può essere modificato vPtr[4] e *(vPtr+4) sono anche notazioni equivalenti notazione con puntatore e indice
9
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio #include #include main(){ int i, offset, b[ ]={10,20,30,40}; int *bPtr=b; printf(stampa del vettore con notazione con indici); for (i=0;i<=3;i++) printf(b[%d]=%d\n,i,b[i]); printf(stampa del vettore con notazione con puntatore e offset); for (offset=0;offset<=3;offset++) printf(*(bPtr+%d)=%d\n,offset,*(bPtr+offset)); printf(stampa del vettore con notazione con puntatore e indice); for (i=0;i<=3;i++) printf(bPtr[%d]=%d\n,i,bPtr[i]); return 0; } b[0]=10 b[1]=20 b[2]=30 b[3]=40 *(bPtr+0)=10 *(bPtr+1)= 20 *(bPtr+2)= 30 *(bPtr+3)= 40 bPtr[0]=10 bPtr[1]=20 bPtr[2]=30 bPtr[3]=40
10
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Alcuni esercizi sulle stringhe… Si scriva una funzione che copia la stringa s2 nel vettore s1. /*Pre: dim del vettore s1 sufficienti per contenere s2*/ /*Post: s1 contiene la stringa s2*/ void stringcopy(char *s1, char *s2) { for (;*s2 !='\0';s1++,s2++) *s1=*s2;*s1='\0';}
11
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Alcuni esercizi sulle stringhe… /*Post: confronta s1 e s2. Restituisce -1 se s1 e' minore in ordine lessicografico di s2, 0 se sono uguali,1 se s1 e' maggiore in ordine lessicografico di s2 */ int stringcmp(char *s1, char *s2) { while (*s1==*s2) { if (*s1=='\0') return 0; s1++;s2++;} if (*s1 == '\0') return -1; else if (*s2 == '\0') return 1; else return (((*s1 - *s2)>0)?1:-1); }
12
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 1, Compito B Si scriva una funzione che dato un vettore di interi ORDINATO calcoli il numero di valori che compaiono ripetuti almeno una volta nel vettore
13
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Soluzioni compito B /* conta il numero di elementi del vettore che vengono ripetuti */ int numRipetizioni (int vett[ ], int n) { int check; int done = 0; int count = 0; int i = 0; check = vett[0]; for (i = 1; i < n; i++) { if (check == vett[i]) { if(done == 0) { done = 1; count++;}} else { check = vett[i]; done = 0; }}
14
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007
15
Esercizio 2, compito D Denominiamo un elemento di una matrice di interi n*m un minimo diagonale se è lelemento con il valore (strettamente) minore tra quelli delle (due) diagonali a cui appartiene. Si scriva una funzione che data una matrice di interi ed un intero h calcoli il numero dei suoi minimi diagonali con valore > h
16
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Soluzione esercizio int minimoDiagonale2(int righe, int colonne, int matrix[][colonne], int h) { int k, i,j ; int count = 0; for (i = 0; i < righe; i++) { for (j = 0; j < righe; j++) { if (matrix[i][j] > h) { if (controlloDiagonale1(colonne, i, j, matrix) && if (controlloDiagonale1(colonne, i, j, matrix) && controlloDiagonale2(colonne, i, j, matrix) && controlloDiagonale2(colonne, i, j, matrix) && controlloDiagonale3(righe, colonne, i, j, matrix) && controlloDiagonale3(righe, colonne, i, j, matrix) && controlloDiagonale4(righe, colonne, i, j, matrix)) { controlloDiagonale4(righe, colonne, i, j, matrix)) {count++;}}}} return count; }
17
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Sol esercizio 2 compito D int controlloDiagonale1(int num_colonne, int indice_riga, int indice_colonna, int matrix[][num_colonne]) { int valore = matrix[indice_riga][indice_colonna]; indice_riga--;indice_colonna++; while (indice_riga >= 0 && indice_colonna = 0 && indice_colonna < num_colonne) { if (valore >= matrix[indice_riga][indice_colonna]) { return 0; } else { indice_riga--;indice_colonna++;}} return 1; }
18
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Sol esercizio 2 compito D int controlloDiagonale2(int num_colonne, int indice_riga, int indice_colonna, int matrix[][num_colonne]) { int valore = matrix[indice_riga][indice_colonna]; indice_riga--;indice_colonna--; while (indice_riga >= 0 && indice_colonna >= 0) { if (valore >= matrix[indice_riga][indice_colonna]) { return 0; } else { indice_riga--;indice_colonna--;}} return 1; }
19
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Sol esercizio 2 compito D int controlloDiagonale3(int num_righe, int num_colonne, int indice_riga, int indice_colonna, int matrix[][num_colonne]) { int valore = matrix[indice_riga][indice_colonna]; indice_riga++;indice_colonna--; while (indice_riga = 0) { if (valore >= matrix[indice_riga][indice_colonna]) { return 0; } else { indice_riga++;indice_colonna--;}} return 1; }
20
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Sol esonero 2 compito D int controlloDiagonale4(int num_righe, int num_colonne, int indice_riga, int indice_colonna, int matrix[][num_colonne]) { int valore = matrix[indice_riga][indice_colonna]; indice_riga++;indice_colonna++; while (indice_riga < num_righe && indice_colonna < num_colonne) { if (valore >= matrix[indice_riga][indice_colonna]) { return 0; } else { indice_riga++;indice_colonna++;}} return 1; }
21
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 2 compito B Denominiamo un elemento di una matrice di interi n*m un massimo diagonale se è lelemento con il valore (strettamente) maggiore tra quelli delle (due) diagonali a cui appartiene. Si scriva una funzione che data una matrice di interi calcoli il numero dei suoi massimi diagonali.
22
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esempio
23
Compito B, secondo esercizio int massimoDiagonale(int righe, int colonne, int matrix[][colonne]) { int k, i,j ; int count = 0; /*scorre le diagonali che partono da (i, 0) con "i" indice di riga e controlla se tale diagonale contiene un massimo diagonale. In caso affermativo aumenta il contatore*/ for (k = 0; k < righe; k++) { count += esisteMassimoDiagonale(righe, colonne, k, 0, matrix); } /*scorre le diagonali che partono da (0, j) con "j" indice di colonna (j > 0 perché tale caso è già stato controllato nel for precedente) e controlla se tale diagonale contiene un massimo diagonale. In caso affermativo aumenta il contatore*/ for (k = 1; k < colonne; k++) { count += esisteMassimoDiagonale(righe, colonne, 0, k, matrix); } return count; }
24
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Compito B, secondo esercizio int esisteMassimoDiagonale(int num_righe, int num_colonne, int indice_riga, int indice_colonna, int matrix[ ][num_colonne]) { int i, j, k, aux_riga, aux_colonna; int check = matrix[indice_riga][indice_colonna]; aux_riga = indice_riga; aux_colonna = indice_colonna; j = aux_colonna + 1; i = aux_riga + 1; while (i < num_righe && j < num_colonne) { if (check < matrix[i][j]) { check = matrix[i][j]; aux_riga = i; aux_colonna = j; } else { if (check == matrix[i][j]) { aux_riga = -1; aux_colonna = -1; }}i++;j++;}
25
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 …fine funzione int check_diagonale1 = 1; int check_diagonale2 = 1; int uscita; if (aux_riga != -1) { i = aux_riga - 1; j = aux_colonna + 1; uscita = 1; while (i >= 0 && j = 0 && j < num_colonne && uscita) { if (matrix[aux_riga][aux_colonna] <= matrix[i][j]) { check_diagonale1 = 0; uscita = 0; } else { i--;j++;}}
26
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 ….fine funzione if (check_diagonale1) { i = aux_riga + 1; j = aux_colonna - 1; uscita = 1; while (i = 0 && uscita) { if (matrix[aux_riga][aux_colonna] <= matrix[i][j]) { check_diagonale2 = 0; uscita = 0; } else { i++;j--;}}} if (check_diagonale1 && check_diagonale2) { return 1; }} return 0; } Siamo allinterno di if aux_riga !=-1
27
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Terzo esercizio, compito B void eliminaInvertiStringa(int k) { char parola[255]; char parola[255]; int count = 0; int count = 0; char testo[255]; char testo[255]; char c; char c; while ((c = getchar()) != EOF) { while ((c = getchar()) != EOF) { testo[count] = c; testo[count] = c; count++; count++; } testo [count] = '\0'; testo [count] = '\0'; int len = strlen(testo); count=0; while (len > 0) { if (testo[len-1] == '\n' || testo[len-1] == ' ') { parola[count] = '\0'; if (strlen(parola) <= k) { printf("%s",parola);} count = 0; if (testo[len-1] == '\n') {printf("\n"); } if (testo[len-1]== ) {printf( ); } } else { parola[count] = testo[len-1]; count++;}len--;} if (strlen(parola) <= k) { parola[count] = '\0'; printf("%s ",parola); }} Prende da input un testo e lo memorizza in una stringa Calcola la lunghezza della stringa Contenente il testo Stampa in ordine invertito le parole che sono di al massimo k caratteri A mano a mano che legge una parola La mette in un vettore di appoggio parola
28
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Soluzioni compito D Esercizio 1, compito D Si scriva una funzione che dato un vettore di interi verifichi se è vero che ogni elemento del vettore contenente un valore dispari abbia un valore maggiore alla somma degli elementi successivi.
29
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 1, compito D int dispariMaggiore (int vett[], int n) { int somma = vett[n-1]; int i; for (i = n-2; i >= 0; i--) { if ((vett[i] % 2 != 0) && vett[i] <= somma) { return 0; } somma += vett[i]; } return 1; } /*Pre: vettore non vuoto*/
30
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 3, compito D Si scriva una funzione che prenda da input una stringa di testo composto da sequenze di caratteri divise da spazi e ritorni a capo. La funzione stampa i caratteri del testo in ordine invertito dopo aver cancellato le sequenze di caratteri del testo che contengono cifre. Vediamo la variante in cui invece il testo sia dato in una stringa
31
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Soluzione esercizio 3, compito D void eliminaInvertiStringaNumeri(char testo[]) { int len = strlen(testo); char parola[255]; int count = 0; int check_num = 1; while (len > 0) { if (testo[len-1] == '\n' || testo[len-1] == ' ' || testo[len-1] == '\0') { parola[count] = '\0'; if (check_num) { printf("%s",parola);} else { check_num = 1; } count = 0; if (testo[len-1] == '\n') { printf("\n");} if (testo[len-1] == ') { printf( "); }} else { parola[count] = testo[len-1]; if (parola[count] >= '0' && parola[count] = '0' && parola[count] <= '9') { check_num = 0; }count++;}len--;} if (check_num) { parola[count] = '\0'; printf("%s ",parola); }} /*Pre: stringa di testo contenente solo Caratteri alfanumerici, spazi e newline*/
32
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Alcuni esercizi sulle stringhe si scriva una funzione che, date due stringhe, restituisce 1 se la prima stringa compare come sottostringa della seconda, 0 altrimenti. Se la prima stringa e' vuota restituisce 1 (una stringa vuota e' sottostringa di q.siasi stringa. Se la seconda stringa e' vuota e la prima no allora restituisce 0.
33
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Alcuni esercizi sulle stringhe int findstr (char *s1, char *s2) { char *temp_s1; char *temp_s2; while (*s2!='\0'){ temp_s2=s2;temp_s1=s1; while ((*s1 == *s2)&&(*s1!='\0')&&(*s2!='\0')) {s1++;s2++;} if (*s1=='\0') return 1; else if (*s2=='\0') return 0; else{s2=temp_s2+1;s1=temp_s1;}} return ((s1=='\0')?1:0); }
34
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Vettori di puntatori I vettori possono contenere elementi di tipo puntatore Esempio: array di stringhe const char *suit[4]={Cuori,Quadri,Picche,Fiori}; Cuori\0 suitFiori\0 Quadri\0 Picche\0 Gli elementi di suit sono puntatori alla posizione dove è memorizzato il primo carattere di ciascuna stringa ciascuno punta in maniera Stabile ad una determinata stringa La memoria allocata per suit è quella necessaria per contenere 4 puntatori Ciascuna stringa ha poi allocata memoria separatamente per Contenerne i caratteri incluso quello di fine stringa 6200 3100
35
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Vettori di puntatori I vettori possono contenere elementi di tipo puntatore Esempio: array di stringhe const char *suit[4]={Cuori,Quadri,Picche,Fiori}; Cuori\0 suitFiori\0 Quadri\0 Picche\0 Non si poteva usare una matrice di caratteri? Si MA luso di vettori di puntatori a caratteri fa risparmiare memoria Per ogni stringa Si alloca la memoria sufficiente a memorizzare la stringa NON la memoria necessaria a memorizzare la stringa più lunga 6200 3100
36
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio Si scriva un programma che mescoli un mazzo di carte, stampando lordine delle carte ottenuto Cuori Quadri Picche Fiori 0 1 2 3 011011129 Asso Due Dieci Fante Donna Re mazzo_carte
37
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Pseudocodice Inizializza la matrice mazzo_carte a 0 Inizializza una variabile contatore k a 1 Fino a quando non è stato assegnato un ordine a ciascuna carta (52 iterazioni) – Scegli la prossima carta Scegli casualmente una riga i Scegli casualmente una riga i Scegli casualmente una colonna j Se mazzo_carte[i][j] è diverso da zero scegli una nuova riga e colonna, ALTRIMENTI mazzo_carte[i][j]=k incrementa k Stampa una a una le carte nellordine selezionato Critico …potrei avere lunghe attese (attesa infinita) prima di trovare una posizione libera. Come potrei risolvere il problema? Posso scegliere casualmente solo tra le posizioni non ancora riempite per esercizio
38
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Codice #include<stdio.h>#include<stdlib.h>#include<time.h> void shuffle(int wDeck[ ][13]); void deal(const int wDeck[ ][13], const char *wFace[ ], const char *wsuit[ ]);
39
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Codice int main() { const char *suit[4]={Cuori,Quadri,Picche,Fiori}; const char *face[13]={Uno,Due,Tre,Quattro, Cinque,Sei,Sette,Otto,Nove,Dieci,Fante, Donna, Re}; int deck[4][13]={0}; srand(time(0));shuffle(deck);deal(deck,face,suit);} Alloco memoria per una matrice di 52 interi. Inizializzo la matrice a 0
40
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Shuffle void shuffle(int wDeck[ ][13]) { int i,j,k; for (k=1; k<=52; k++) { do{i=rand()%4;j=rand()%13; } while (wDeck[i][j] !=0); wDeck[i][j]=k; }}
41
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Shuffle Cuori Quadri Picche Fiori 0 1 2 3 011011129 Asso Due Dieci Fante Donna Re k=1 i 1 j 3 1 k=2 i 3 j 10 2
42
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Shuffle Cuori Quadri Picche Fiori 0 1 2 3 011011129 Asso Due Dieci Fante Donna Re SCEGLIAMO UN ALTRO i e j, LA POSIZIONE È GIA OCCUPATA i 1 j 3 1 k=3 i 2 j 12 2 3
43
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Stampa delle carte nellordine selezionato void deal(const int wDeck[][13],const char *wFace[ ], const char *wSuit[ ]) { int i,j,k; for (k=1;k<=52;k++){ for (i=0;i<=3;i++){ for (j=0;j<=12;j++){ if (wDeck[i][j]==k){ printf(%s di %s\n,wFace[j],wSuit[i]); }}}}} Quattro di Quadri Fante di Fiori Re di Picche --- Scandiamo sempre tutta la matrice anche quando abbiamo trovato lelemento che corrisponde alla k-esima carta inefficiente. Qualche idea su come evitare questo problema?
44
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Puntatori a funzioni Un nome di funzione indica lindirizzo di memoria in cui è memorizzata la prima istruzione della funzione Esempio di uso: una versione del bubblesort che consenta di inserire da input se il vettore deve essere ordinato in ordine crescente o decrescente
45
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007Bubblesort#include<stdio.h> #define SIZE 10 void bubble(int work[ ], const int size, int (*compare)(int a,int b)); int ascending(int a, int b); int descending(int a,int b); Puntatore ad una funzione che prende come parametri due interi e restituisce un intero Compare è un puntatore a funzione
46
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007Bubblesort int main() { int order; /* 1 per ordine crescente, 2 per decrescente*/ int counter; int a[SIZE]={2,6,4,8,10,12,89,68,45,37}; printf(si inserisca 1 per ordinare in ordine crescente, 2 per un ordinamento decrescente del vettore \n); scanf(%d, &order); printf(dati nellordine originale \n); for (counter=0;counter<SIZE;counter++){ printf(%d,a[counter]);}if(order==1){bubble(a,SIZE,ascending);}else{bubble(a,SIZE,descending);} for (counter=0,counter<SIZE; counter++){ printf(%d,a[counter]);} return 0; } puntatore a funzione
47
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Bubble void bubble(int work[ ],const int size, int (*compare)(int a, int b)) { int pass; int count; void swap(int *element1Ptr,int *element2Ptr); for (pass=1;pass<size;pass++){ for (count=0;count<size-1;count++){ if ((*compare)(work[count],work[count+1])){ swap(&work[count],&work[count+1]);}}}} compare è un puntatore ad una funzione che prende due parametri interi e restituisce un intero int (*) (int,int); un puntatore a funzione è dereferenziato per usare la funzione Invoca la funzione puntata da compare con parametri work[count] e work[count+1]
48
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Swap, ascending, descending void swap(int *element1Ptr, int *element2Ptr) { int hold; hold=*element1Ptr;*element1Ptr=*element2Ptr;*element2Ptr=hold;} /*ritorna 1 se non si segue lordinamento crescente*/ int ascending(int a,int b) { return b<a; } int descending(int a,int b) { return b>a; } A seconda che si voglia ordinare in ordine crescente o decrescente occorre testare due condizioni diverse per verificare se due elementi consecutivi sono ordinati correttamente o meno printf(si inserisca 1 per ordinare in ordine crescente, 2 per un ordinamento decrescente del vettore \n); scanf(%d, &order); printf(dati nellordine originale \n); for (counter=0;counter<SIZE;counter++){ printf(%d,a[counter]);}if(order==1){bubble(a,SIZE,ascending);}else{bubble(a,SIZE,descending);}
49
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Puntatori a funzione (secondo esempio) Un utente seleziona unopzione da un menu. Ciascuna opzione è servita da una funzione differente. I diversi puntatori a funzione sono memorizzati in un array di puntatori a funzione. La scelta dellutente fornisce lindice del vettore. Il puntatore a funzione è usato per invocare la funzione opportuna in base alla scelta dellutente.
50
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007Codice#include<stdio.h> void function1(int a); void function2 (int b); void function3 (int c); int main() { void (*f[3])(int)={function1,function2,function3}; int choice,i; printf(inserisci la scelta della funzione da invocare: 0, 1, 2 a seconda che vogliate moltiplicare per uno, due o tre il valore inserito. Inserire il valore 3 per terminare lesecuzione); scanf(%d,&choice); printf(inserisci intero \n); scanf(%d,&i); while(choice>=0 && choice =0 && choice <3){(*f[choice])(i); printf(inserisci la scelta della funzione da invocare: 0, 1, 2 a seconda che vogliate moltiplicare per uno, due o tre il valore inserito. Inserire il valore 3 per terminare lesecuzione); scanf(%d, &choice); printf(inserisci intero \n); scanf(%d,&i);} return 0; } inizializza un array di tre puntatori a funzione Queste funzioni prendono in input un intero e non restituiscono valori invoca la funzione puntata da f[choice] sul valore intero inserito da input i
51
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Codice delle tre funzioni… void function1(int a) { printf(il valore di a moltiplicato per uno è %d\n,a*1); } void function2(int a) { printf(il valore di a moltiplicato per due è %d\n,a*2); } void function3(int a) { printf(il valore di a moltiplicato per tre è %d\n,a*3); }
52
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007
53
Argomenti avanzati sulle funzioni… Classi di memoria Regole di scope
54
Classi di memoria Una variabile ha associato un tipo, un nome, una dimensione ed un valore Altri attributi di una variabile sono la sua classe di memoria – auto – register –extern –static il periodo durante il quale lidentificatore ha associata memoria (storage duration) il periodo durante il quale lidentificatore ha associata memoria (storage duration) lo scope (in quali parti del programma si può far riferimento alla variabile) linkage (se il programma è suddiviso in più file se lidentificatore può essere usato solo in questo file oppure in altri file previa opportune dichiarazioni) ARGOMENTO CHE TRATTERETE AD ESERCITAZIONE/PROG2
55
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Automatic storage duration Classi di memoria auto autoregister Le variabili di tipo auto o register permangono in memoria fino a quando è attivo il blocco di istruzioni allinterno del quale la variabile è definita Le variabili locali alle funzioni sono tipicamente di tipo auto (è la loro classe di memoria di default) Se una variabile è di tipo register si suggerisce che venga memorizzata in un registro I compilatori sanno ottimizzare luso dei registri meglio di un programmatore I compilatori sanno ottimizzare luso dei registri meglio di un programmatore possono decidere di ignorare la richiesta di mettere in un registro una variabile possono decidere di ignorare la richiesta di mettere in un registro una variabile Le variabili viste Finora erano implicitamente dichiarate come auto Se dichiarate allinizio del main è loro allocata memoria fino alluscita dal programma se dichiarate allinizio di una funzione la variabile ha allocata memoria fino a quando non si esce dalla funzione register int counter=1; dice che la variabile intera counter dovrebbe essere memorizzata in un registro e inizializzata a 1
56
Static storage duration Le parole chiave extern extern static static sono usate per identificare variabili e funzioni di tipo static storage Memoria è allocata una volta per tutte e le variabili sono inizializzate allinizio del programma. Tale memoria è disponibile per lintera durata del programma Le variabili globali sono di tipo extern per default. Sono dichiarate fuori da ogni funzione e mantengono memoria a loro allocata durante lintera durata del programma. Possono essere riferite da una qualsiasi funzione che segue la loro dichiarazione. Le variabili di tipo static invece sono note solo allinterno della funzione dove sono definite. Tuttavia quando si esce dalla funzione si continua a memorizzare il loro valore. La prossima volta che si invoca la funzione la variabile locale static avrà come valore quello che aveva alla fine della precedente invocazione. static int count=1;
57
Regole di scope Lo scope di un identificatore è la porzione del programma allinterno della quale si può fare riferimento allidentificatore – function scope – file scope –block scope –function-prototype scope etichette usate nel costrutto switch possono essere usate solo allinterno della funzione nella quale compaiono (e possono essere riferite in qualsiasi punto della funzione) Un identificatore dichiarato allesterno di ogni funzione ha uno scope di tipo file scope Possono essere riferite in qualsiasi punto allinterno del file a partire dal punto in cui lidentificatore è dichiarato Esempi: variabili globali, definizioni di funzioni, prototipi)
58
Regole di scope Lo scope di un identificatore è la porzione del programma allinterno della quale si può fare riferimento allidentificatore – function scope – file scope –block scope –function-prototype scope Identificatori block scope possono essere riferiti allinterno del Blocco in cui sono dichiarate Il blocco è delimitato da {} Variabili static hanno uno scope di blocco Variabili locali ad una funzione hanno scope di blocco Gli unici identificatori di tipo function prototype scope sono quelli usati nella lista dei parametri di un prototipo di funzione. Dato che tali nomi, se usati, sono ignorati dal compilatore, hanno valore solo allinterno del prototipo. Gli stessi identificatori possono essere riutilizzati in altre parti del programma senza problemi di ambiguità
59
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… #include #include void useLocal (void); void useStaticLocal (void); void useGlobal (void); int x=1; /*variabile globale*/ int main() { int x=5;/*variabile locale al main*/ printf(il valore di x allinterno dello scope più esterno del main è: %d,x); {/*comincia un nuovo scope*/ int x=7; /*variabile locale al blocco*/ printf(il valore di x allinterno dello scope più interno del main è: %d,x); } printf(il valore di x nello scope più esterno del main è: %d, x); useLocal();useStaticLocal();useGlobal();useLocal();useStaticLocal();useGlobal(); return 0; } Se lo stesso identificatore è usato in un blocco più interno allinterno del blocco interno vale la definizione e inizializzazione del blocco interno. Il valore di x allinterno dello scope più esterno del main è: 5 Il valore di x allinterno dello scope più interno del main è: 7 Il valore di x allinterno dello scope più esterno del main è: 5
60
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… void useLocal (void) { int x=25; /*è di classe di memoria auto*/ printf() printf(valore di x entrati in useLocal, allinizio della funzione: %d\n,x); x++; printf(valore di x entrati in useLocal, alla fine della funzione: %d\n,x); }
61
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… #include #include void useLocal (void); void useStaticLocal (void); void useGlobal (void); int x=1; /*variabile globale*/ int main() { int x=5;/*variabile locale al main*/ printf(il valore di x allinterno dello scope più esterno del main è: %d,x); {/*comincia un nuovo scope*/ int x=7; /*variabile locale al blocco*/ printf(il valore di x allinterno dello scope più interno del main è: %d,x); } printf(il valore di x nello scope più esterno del main è: %d, x); useLocal();useStaticLocal();useGlobal();useLocal();useStaticLocal();useGlobal(); return 0; } Il valore di x entrati in UseLocal allinizio della funzione è: 25 Il valore di x entrati in UseLocal alla fine della funzione è: 26
62
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… void useStaticLocal() { static int x=50; /*inizializzata solo la prima volta che si entra nella funzione*/ printf(local static vale %d allinizio della funzione useStaticLocal,x); x++; printf(local static vale %d alla fine della funzione useStaticLocal,x); }
63
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… void useGlobal() { printf(global x vale %d allentrata di useGlobal\n,x); x*=10; printf(global x vale %d alla fine di useGlobal\n,x); }
64
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… #include #include void useLocal (void); void useStaticLocal (void); void useGlobal (void); int x=1; /*variabile globale*/ int main() { int x=5;/*variabile locale al main*/ printf(il valore di x allinterno dello scope più esterno del main è: %d,x); {/*comincia un nuovo scope*/ int x=7; /*variabile locale al blocco*/ printf(il valore di x allinterno dello scope più interno del main è: %d,x); } printf(il valore di x nello scope più esterno del main è: %d, x); useLocal();useStaticLocal();useGlobal();useLocal();useStaticLocal();useGlobal(); return 0; } local static vale 50 allinizio della funzione useStaticLocal local static vale 51 alla fine della funzione useStaticLocal
65
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… #include #include void useLocal (void); void useStaticLocal (void); void useGlobal (void); int x=1; /*variabile globale*/ int main() { int x=5;/*variabile locale al main*/ printf(il valore di x allinterno dello scope più esterno del main è: %d,x); {/*comincia un nuovo scope*/ int x=7; /*variabile locale al blocco*/ printf(il valore di x allinterno dello scope più interno del main è: %d,x); } printf(il valore di x nello scope più esterno del main è: %d, x); useLocal();useStaticLocal();useGlobal();useLocal();useStaticLocal();useGlobal(); return 0; } Global x vale 1 allentrata di useGlobal Global x vale 10 alla fine di useGlobal
66
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… #include #include void useLocal (void); void useStaticLocal (void); void useGlobal (void); int x=1; /*variabile globale*/ int main() { int x=5;/*variabile locale al main*/ printf(il valore di x allinterno dello scope più esterno del main è: %d,x); {/*comincia un nuovo scope*/ int x=7; /*variabile locale al blocco*/ printf(il valore di x allinterno dello scope più interno del main è: %d,x); } printf(il valore di x nello scope più esterno del main è: %d, x); useLocal();useStaticLocal();useGlobal();useLocal();useStaticLocal();useGlobal(); return 0; } Il valore di x entrati in UseLocal allinizio della funzione è: 25 Il valore di x entrati in UseLocal alla fine della funzione è: 26
67
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… #include #include void useLocal (void); void useStaticLocal (void); void useGlobal (void); int x=1; /*variabile globale*/ int main() { int x=5;/*variabile locale al main*/ printf(il valore di x allinterno dello scope più esterno del main è: %d,x); {/*comincia un nuovo scope*/ int x=7; /*variabile locale al blocco*/ printf(il valore di x allinterno dello scope più interno del main è: %d,x); } printf(il valore di x nello scope più esterno del main è: %d, x); useLocal();useStaticLocal();useGlobal();useLocal();useStaticLocal();useGlobal(); return 0; } local static vale 51 allinizio della funzione useStaticLocal local static vale 52 alla fine della funzione useStaticLocal
68
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… #include #include void useLocal (void); void useStaticLocal (void); void useGlobal (void); int x=1; /*variabile globale*/ int main() { int x=5;/*variabile locale al main*/ printf(il valore di x allinterno dello scope più esterno del main è: %d,x); {/*comincia un nuovo scope*/ int x=7; /*variabile locale al blocco*/ printf(il valore di x allinterno dello scope più interno del main è: %d,x); } printf(il valore di x nello scope più esterno del main è: %d, x); useLocal();useStaticLocal();useGlobal();useLocal();useStaticLocal();useGlobal(); return 0; } Global x vale 10 allentrata di useGlobal Global x vale 100 alla fine di useGlobal
69
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Ricorsione Abbiamo visto come un problema complesso possa essere scomposto in task, ciascuno realizzato tramite una funzione Una funzione può invocare altre funzioni E possibile anche invocare la STESSA funzione, su un input diverso – Un task complesso può essere risolto invocando la funzione che realizza il task su dei sottoproblemi, usando la capacità di svolgere il task su sottoproblemi per riuscire a svolgere il task sullintero problema ricorsione ricorsione
70
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Ricorsione…un esempio Vogliamo scrivere una funzione che consenta di calcolare il fattoriale n! n!= n*(n-1)*(n-2)*(n-3)*…*2*1 Approccio ricorsivo: – – Supponiamo di poter invocare ricorsivamente la funzione su interi n < n e di poter usare tale invocazione per calcolare il fattoriale di n – – Possiamo sfruttare il fatto che n!=n*(n-1)! – –Per calcolare il fattoriale di n invoco la funzione fatt su n-1 e moltiplico il risultato per n Abbiamo ridotto la complessità del problema esprimendo la soluzione in funzione della risoluzione di problemi meno complessi sfruttando il fatto che tramite chiamata ricorsiva riusciamo a risolvere su problemi più piccoli per trovare la soluzione del problema più complesso
71
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Fattoriale (versione ricorsiva) int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } Caso base. Occorre saper risolvere direttamente i casi base.
72
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 5! Viene invocata x=fatt(5); int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } PRIMA INVOCAZIONE DI FATT fatt(5) Allentrata della funzione si alloca memoria per la var. locale n Si copia in tale locazione il valore 5 n 5Si invoca fatt(4) 3200
73
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 5! Viene invocata fatt(4); int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } SECONDA INVOCAZIONE DI FATT fatt(4) Allentrata della funzione si alloca memoria per la var. locale n, relativa A QUESTA INVOCAZIONE DI FUNZIONE Si copia in tale locazione il valore 4 n 4Si invoca fatt(3) 5200
74
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 5! Viene invocata fatt(3); int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } TERZA INVOCAZIONE DI FATT fatt(3) Allentrata della funzione si alloca memoria per la var. locale n, relativa A QUESTA INVOCAZIONE DI FUNZIONE Si copia in tale locazione il valore 3 n 3Si invoca fatt(2) 7800
75
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 5! Viene invocata fatt(2); int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } QUARTA INVOCAZIONE DI FATT fatt(2) Allentrata della funzione si alloca memoria per la var. locale n, relativa A QUESTA INVOCAZIONE DI FUNZIONE Si copia in tale locazione il valore 2 n 2Si invoca fatt(1) 9800
76
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 5! Viene invocata fatt(1); int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } QUINTA INVOCAZIONE DI FATT fatt(1) Allentrata della funzione si alloca memoria per la var. locale n, relativa A QUESTA INVOCAZIONE DI FUNZIONE Si copia in tale locazione il valore 1 n 1 Si restituisce il controllo alla funzione chiamante fatt(2), restituendo 1 3900 fatt(5) fatt(4) fatt(2) fatt(3) fatt(1) Fondamentale che La sequenza di Invocazioni termini SEMPRE con linvocazione della funzione su un caso che sappiamo risolvere direttamente (caso base) La memoria allocata per n viene rilasciata
77
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 5! Viene invocata fatt(2); int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } QUARTA INVOCAZIONE DI FATT fatt(2) Allentrata della funzione si alloca memoria per la var. locale n, relativa A QUESTA INVOCAZIONE DI FUNZIONE Si copia in tale locazione il valore 2 n 2 9800 restituisce 1 Viene calcolato fatt(2) 2*1=2 e viene restituito tale valore alla funzione chiamante fatt(3) fatt(5) fatt(4) fatt(2) fatt(3) fatt(1)
78
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 5! Viene invocata fatt(3); int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } TERZA INVOCAZIONE DI FATT fatt(3) n 3 7800 restituisce 2 Viene calcolato fatt(3) 3*2=6 e viene restituito tale valore alla funzione chiamante fatt(4) fatt(5) fatt(4) fatt(2) fatt(3) fatt(1)
79
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 5! Viene invocata fatt(4); int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } SECONDA INVOCAZIONE DI FATT fatt(4) n 4 5200 restituisce 6 Viene calcolato fatt(4) 4*6=24 e viene restituito tale valore alla funzione chiamante fatt(5) fatt(4) fatt(2) fatt(3) fatt(1)
80
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 5! Viene invocata x=fatt(5); int fatt (int n) { if (n==1) return 1; else return (fatt(n-1)*n); } PRIMA INVOCAZIONE DI FATT fatt(5) n 5 3200 restituisce 24 Viene calcolato fatt(5) 5*24=120 e viene restituito tale valore alla funzione chiamante main() fatt(5) fatt(4) fatt(2) fatt(3) fatt(1)
81
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Alcuni commenti… Approccio ricorsivo – richiede linvocazione di molte chiamate a funzione, di allocare ogni volta memoria per i parametri e le variabili locali può essere inefficiente può essere inefficiente TUTTAVIA ragionare in modo ricorsivo è molto utile e vedrete di qui a poco (PROG2) che esistono strutture dati molto importanti quali gli alberi sui quali si riesce a ragionare efficamente solo in modo ricorsivo RAGIONARE IN MODO RICORSIVO E COMPLESSO MA E Q.SA DI FONDAMENTALE PER UN INFORMATICO!! Abbiamo visto cosa succede in memoria quando invochiamo una sequenza di chiamate ricorsive…è importante capire come si ragiona ricorsivamente
82
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Come si ragiona ricorsivamente INPUT OUTPUT funzione Se siamo in grado di descrivere correttamente cosa fa la funzione (postcondizione) Dobbiamo chiederci se possiamo usare il fatto che la funzione possa essere applicata su input più piccoli per risolvere il caso generale Se gli output della invocazioni su casi più piccoli possono essere elaborati ed usati per trovare la soluzione al problema (OUTPUT) per il caso più grande AVER DETERMINATO IL MODO DI FARE CIO CI DARA IL NOSTRO CODICE RICORSIVO output1output2
83
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Come si ragiona ricorsivamente INPUT OUTPUT funzione Se siamo in grado di descrivere correttamente cosa fa la funzione (postcondizione) Dobbiamo chiederci se possiamo usare il fatto che la funzione possa essere applicata su input più piccoli per risolvere il caso generale Se gli output della invocazioni su casi più piccoli possono essere elaborati ed usati per trovare la soluzione al problema (OUTPUT) per il caso più grande AVER DETERMINATO IL MODO DI FARE CIO CI DARA IL NOSTRO CODICE RICORSIVO output1output2 Sarà poi fondamentale individuare i casi base e assicurarci che tutte le sequenze di chiamate ricorsive terminino sempre con linvocazione di un caso base
84
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio… SI scriva una funzione ricorsiva che dati due numeri interi a e b calcoli a+b Se so calcolare x+y, x<=a, y<b, come posso usarlo per calcolare a+b a+b=(a+b-1)+1 a+b=(a+b-1)+1 Calcolato dallinvocazione della funzione su a e b-1 Caso base: se b==0, a+b=a
85
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007Soluzione int somma (int a, int b) { if (b==0) return a; else return (somma(a,b-1)+1); } Vediamo cosa succede invocando somma (3,2)
86
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 3+2 Viene invocata x=somma(3,2); int somma (int a, int b) { if (b==0) return a; else return (somma(a,b-1)+1); } PRIMA INVOCAZIONE DI SOMMA Allentrata della funzione si alloca memoria per le var. locale a e b Si copia in tali locazioni i valori 3 e 2 a 3 Si invoca somma(3,1) 3200 b 2 3800
87
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 3+2 Viene invocata somma(3,1); int somma (int a, int b) { if (b==0) return a; else return (somma(a,b-1)+1); } SECONDA INVOCAZIONE DI SOMMA Allentrata della funzione si alloca memoria per le var. locale a e b RELATIVE A QUESTA INVOCAZIONE Si copia in tali locazioni i valori 3 e 1 a 3 Si invoca somma(3,0) 5700 b 1 8100
88
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 3+2 Viene invocata somma(3,0); int somma (int a, int b) { if (b==0) return a; else return (somma(a,b-1)+1); } TERZA INVOCAZIONE DI SOMMA Allentrata della funzione si alloca memoria per le var. locale a e b RELATIVE A QUESTA INVOCAZIONE Si copia in tali locazioni i valori 3 e 0 a 3 Si ritorna il controllo restituendo 3 2700 b 0 9000 somma(3,2) somma(3,1) somma(3,0) La memoria allocata viene rilasciata
89
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 3+2 Viene invocata somma(3,1); int somma (int a, int b) { if (b==0) return a; else return (somma(a,b-1)+1); } SECONDA INVOCAZIONE DI SOMMA Allentrata della funzione si alloca memoria per le var. locale a e b RELATIVE A QUESTA INVOCAZIONE Si copia in tali locazioni i valori 3 e 1 a 3 Si ritorna il controllo restituendo 4 a somma (3,2) 5700 b 1 8100 La memoria allocata viene rilasciata Ha restituito 3 somma(3,2) somma(3,1) somma(3,0)
90
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di 3+2 Viene invocata somma(3,2); int somma (int a, int b) { if (b==0) return a; else return (somma(a,b-1)+1); } PRIMA INVOCAZIONE DI SOMMA Allentrata della funzione si alloca memoria per le var. locale a e b RELATIVE A QUESTA INVOCAZIONE Si copia in tali locazioni i valori 3 e 2 a 3 Si ritorna il controllo restituendo 5 a main() 3200 b 2 3800 La memoria allocata viene rilasciata Ha restituito 4 somma(3,2) somma(3,1) somma(3,0)
91
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un terzo esempio Calcolo di a*b a*b= a+a+… …+a a*b=(a*(b-1))+a Caso base a*1=aa*0=0 b volte
92
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Moltiplicazione tra due interi int prodotto (int a,int b) { if (b==0) return 0; if (b==1) return a; else return (prodotto(a,b-1)+a); }
93
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un quarto esempio Precondizione: a>=1 Calcolo di a b a b = a*a*… …*a a b =(a b-1 )*a Caso base a 0 =1 b volte
94
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Moltiplicazione tra due interi int potenza (int a,int b) { if (b==0) return 1; else return (potenza(a,b-1)*a); }
95
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Numeri di Fibonacci La serie di Fibonacci 0,1,1,2,3,5,8,13,21,.. Comincia con i numero 0 e 1 ed ha la proprietà che se si conoscono F(i) e F(i+1) allora F(i+2)=F(i+1)+F(i) E una serie che occorre in natura. Il rapporto tra due numeri consecutivi della serie di Fibonacci converge al numero 1.618.. che è chiamata sezione aurea Usare come rapporto tra dimensioni la sezione aurea è esteticamente piacevole usato sin dallantichità in architettura (esempio rapporto tra le dimensioni di una finestra, le dimensioni relative dei lati di una cartolina etc.)
96
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007Codice long Fibonacci (long n) { if ((n==0)||(n==1)) return n; else return (Fibonacci(n-1)+Fibonacci(n-2)); } Calcola F(n)
97
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di Fibonacci(3) Viene invocata x=Fibonacci(3); long Fibonacci (long n) { if ((n==0)||(n==1)) return n; else return (Fibonacci(n-1)+ Fibonacci(n-2));} PRIMA INVOCAZIONE DI FIBONACCI Allentrata della funzione si alloca memoria per le var. n Si copia in tale locazione il valore 3 n 3 Si invoca Fibonacci(2) E Fibonacci(1) 3200 Attenzione: non si può sapere se verrà valutata prima la chiamata Fibonacci(2) O Fibonacci(1)
98
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di Fibonacci(3) Viene invocata Fibonacci(2); long Fibonacci (long n) { if ((n==0)||(n==1)) return n; else return (Fibonacci(n-1)+ Fibonacci(n-2));} SECONDA INVOCAZIONE DI FIBONACCI Allentrata della funzione si alloca memoria per le var. n RELATIVA A QUESTA INVOCAZIONE Si copia in tale locazione il valore 2 n 2 Si invoca Fibonacci(1) E Fibonacci(0) 4000 Attenzione: non si può sapere se verrà valutata prima la chiamata Fibonacci(1) O Fibonacci(0) F(3) F(1)F(2) F(0)F(1)
99
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di Fibonacci(3) Viene invocata Fibonacci(1); long Fibonacci (long n) { if ((n==0)||(n==1)) return n; else return (Fibonacci(n-1)+ Fibonacci(n-2));} TERZA INVOCAZIONE DI FIBONACCI Allentrata della funzione si alloca memoria per le var. n RELATIVA A QUESTA INVOCAZIONE Si copia in tale locazione il valore 1 n 1 Si restituisce al chiamante Fibonacci(2) il valore 1 5900 F(3) F(1)F(2) F(0)F(1) 1
100
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di Fibonacci(3) Viene invocata Fibonacci(0); long Fibonacci (long n) { if ((n==0)||(n==1)) return n; else return (Fibonacci(n-1)+ Fibonacci(n-2));} QUARTA INVOCAZIONE DI FIBONACCI Allentrata della funzione si alloca memoria per le var. n RELATIVA A QUESTA INVOCAZIONE Si copia in tale locazione il valore 0 n 0 Si restituisce al chiamante Fibonacci(2) il valore 0 9900 F(3) F(1)F(2) F(0)F(1) 1 0
101
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di Fibonacci(3) Viene invocata Fibonacci(1); long Fibonacci (long n) { if ((n==0)||(n==1)) return n; else return (Fibonacci(n-1)+ Fibonacci(n-2));} QUINTA INVOCAZIONE DI FIBONACCI Allentrata della funzione si alloca memoria per le var. n RELATIVA A QUESTA INVOCAZIONE Si copia in tale locazione il valore 1 n 1 Si restituisce al chiamante Fibonacci(3) il valore 1 15000 F(3) F(1)F(2) F(0)F(1) 1 0 1
102
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di Fibonacci(3) Viene invocata Fibonacci(2); long Fibonacci (long n) { if ((n==0)||(n==1)) return n; else return (Fibonacci(n-1)+ Fibonacci(n-2));} Allentrata della funzione si alloca memoria per le var. n RELATIVA A QUESTA INVOCAZIONE Si copia in tale locazione il valore 2 n 2 Si restituisce al chiamante Fibonacci(3) il valore 1 4000 1 0 F(3) F(1)F(2) F(0)F(1) 1 0 1 1
103
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Un esempio.. Calcolo di Fibonacci(3) Viene invocata Fibonacci(3); long Fibonacci (long n) { if ((n==0)||(n==1)) return n; else return (Fibonacci(n-1)+ Fibonacci(n-2));} Allentrata della funzione si alloca memoria per le var. n RELATIVA A QUESTA INVOCAZIONE Si copia in tale locazione il valore 3 n 2 Si restituisce al chiamante main il valore 2 3200 1 1 F(3) F(1)F(2) F(0)F(1) 1 0 1 1 2 Numero di chiamate necessarie Per calcolare F(n) dellordine di 2 n complessità esponenziale
104
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007Fibonacci Valore di nF(n)Numero di chiamate di funzione F(n) 001 111 213 325 … 232865792735 2446368150049 2575025242785 … 41165580141535828591 42267914296866988873 La ricorsione in molti casi è utile però può ridurre lefficienza. Numero di chiamate elevato significa che paghiamo un overhead elevato (tempo e spazio) per invocare le funzioni, allocare memoria per le variabili locali
105
Torri di Hanoi La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. A B C
106
Torri di Hanoi La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. A B C Ogni mossa poteva portare allo spostamento di un unico disco E in ogni momento i dischi dovevano essere posizionati in ordine decrescente su ciascuno dei paletti La leggenda narra che il mondo finirà prima che i monaci siano riusciti a completare questo compito!
107
Torri di Hanoi…un esempio La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. A B C Ad esempio il disco viola può essere spostato in una mossa da A a B
108
Torri di Hanoi…un esempio La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. A B C Nella mossa successiva il disco azzurro può essere spostato da A a C Il disco azzurro NON poteva essere spostato da A a B perché tale spostamento non avrebbe soddisfatto il vincolo di ordinamento decrescente dei dischi in B
109
Torri di Hanoi…un esempio La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. La leggenda narra che in un tempio del profondo oriente i monaci fossero occupati nel compito di spostare dei dischi di pietra impilati in ordine di dimensione decrescente in un paletto A,dal paletto (A) al paletto B. Il numero dei dischi era 64, esisteva anche un terzo paletto dappoggio C. A B C Nella mossa successiva non possiamo direttamente spostare il disco verde Possiamo ad esempio prima spostare il disco viola in C e poi il disco verde in B
110
Torri di Hanoi Problema di difficile risoluzione iterativa se abbiamo molti dischi (e dobbiamo trovare un algoritmo che valga sempre, per qualsiasi numero di dischi) Ragionare in modo ricorsivo aiuta a trovare una soluzione A B
111
Torri di Hanoi Cosa vogliamo fare? – Muovere n dischi dal paletto A al paletto B usando C come appoggio Come lo possiamo fare? – Muovere n-1 dischi dal paletto A al paletto C usando B come appoggio A B
112
Torri di Hanoi Cosa vogliamo fare? – Muovere n dischi dal paletto A al paletto B usando C come appoggio Come lo possiamo fare? – Muovere n-1 dischi dal paletto A al paletto C usando B come appoggio –Spostare il disco più grande da A in B A B
113
Torri di Hanoi Cosa vogliamo fare? – Muovere n dischi dal paletto A al paletto B usando C come appoggio Come lo possiamo fare? – Muovere n-1 dischi dal paletto A al paletto C usando B come appoggio –Spostare il disco più grande da A in B –Muovere n-1 dischi da C a B usando A come appoggio A B Chiamate ricorsive
114
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Torri di Hanoi-Codice #include<stdio.h> void hanoi (int,int[ ], int *, int [ ], int *, int [ ], int *); main(){ int i,n,n_A,n_B,n_C; int A[100]={0}; int B[100]={0}; int C[100]={0}; n_A=n_B=n_C=0; printf(inserisci un numero di dischi tra 1 e 100 \n); scanf(%d, &n); while ((n>100)||(n 100)||(n<1)){ printf(inserisci un numero di dischi tra 1 e 100 \n); printf(inserisci un numero di dischi tra 1 e 100 \n); scanf(%d, &n); } for (i=0;i<n;i++) A[i]=i+1;n_A=n; hanoi (n,A,&n_A, B, &n_B, C, &n_C); return 0; } I vettori A, B, C conterranno i dischi (ed il loro ordine) impilati nei pioli A,B, e C Dato un vettore A, n_A indicherà il numero di dischi impilati in A (memorizzati nelle locazioni di memoria 0,…,n_A-1) n_A sarà quindi anche lindice della prossima posizione libera del vettore Numero di dischiVettore che rappresenta il primo piolo Puntatore alla locazione che contiene La prima locazione libera relativa al primo piolo
115
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Torri di Hanoi-Codice #include<stdio.h> void hanoi (int,int[ ], int *, int [ ], int *, int [ ], int *); main(){ int i,n,n_A,n_B,n_C; int A[100]={0}; int B[100]={0}; int C[100]={0}; n_A=n_B=n_C=0; printf(inserisci un numero di dischi tra 1 e 100 \n); scanf(%d, &n); while ((n>100)||(n 100)||(n<1)){ printf(inserisci un numero di dischi tra 1 e 100 \n); printf(inserisci un numero di dischi tra 1 e 100 \n); scanf(%d, &n); } for (i=0;i<n;i++) A[i]=i+1;n_A=n; hanoi (n,A,&n_A, B, &n_B, C, &n_C); return 0; } I dischi hanno associato un indice da 1,..,n I dischi più grandi avranno associato un indice più piccolo Se il primo piolo contiene I dischi in figura il corrispettivo vettore A conterrà nelle prime n_A=4 posizioni i valori 1,2,3,4 4 3 2 1 A 1234 4 n_A
116
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Torri di Hanoi-Codice #include<stdio.h> void hanoi (int,int[ ], int *, int [ ], int *, int [ ], int *); main(){ int i,n,n_A,n_B,n_C; int A[100]={0}; int B[100]={0}; int C[100]={0}; n_A=n_B=n_C=0; printf(inserisci un numero di dischi tra 1 e 100 \n); scanf(%d, &n); while ((n>100)||(n 100)||(n<1)){ printf(inserisci un numero di dischi tra 1 e 100 \n); printf(inserisci un numero di dischi tra 1 e 100 \n); scanf(%d, &n); } for (i=0;i<n;i++) A[i]=i+1;n_A=n; hanoi (n,A,&n_A, B, &n_B, C, &n_C); return 0; } Inizializza i vettori A, B e C a zero n_A,n_B,n_C a zero (i vettori non hanno elementi memorizzati) Prende da input un numero valido di dischi n Mette in A i vari dischi dal più grande al più piccolo (situazione quando si comincia a spostare da A a B i dischi). Si aggiorna coerentemente n_A. Si invoca la funzione hanoi il cui Compito sarà spostare n dischi da A a B seguendo le regole per il movimento dei dischi e mantenendo aggiornate le informazioni sul contenuto e num. Di elementi del vettore
117
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Torri di Hanoi-Codice /*pre: num >=1*/ void hanoi(int num, int a[ ], int *N_a, int b[ ], int *N_b, int c[ ], int *N_c) { if (num==1) {b[(*N_b)]=a[(*N_a)-1];(*N_b)=(*N_b)+1;(*N_a)=(*N_a)-1;}else{hanoi(num-1,a,N_a,c,N_c,b,N_b);b[(*N_b)]=a[(*N_a)-1];(*N_b)=(*N_b)+1;(*N_a)=(*N_a)-1; hanoi (num-1,c,N_c,b,N_b,a,N_a); }} Sposto direttamente da a a b
118
Un esempio hanoi(4,A,&n_A,B,&n_B,C, &n_C); 4 3 2 1 4 n_A 0 n_B 0 n_C A B through C hanoi (3, A, N_a, C, N_c, B, N_b); A C through B
119
Un esempio hanoi(3,A,N_a,C,N_c,B, N_b); 4 3 2 1 400 A C through B hanoi (2, A, N_a, B, N_b, C, N_c); A B through C n_An_Bn_C
120
Un esempio hanoi(2,A,N_a,B,N_b,C, N_c); 4 3 2 1 400 A B through C hanoi (1, A, N_a, C, N_c, B, N_b); A C through B n_An_Bn_C
121
Un esempio hanoi(1,A,N_a,C,N_c,B, N_b); 4 3 2 1 400 A C through B c[n_C]=a[n_A-1]; n_A--; n_C++; n_An_Bn_C
122
Un esempio hanoi(1,A,N_a,C,N_c,B, N_b); 4 3 2 1 301 A C through B c[n_C]=a[n_A-1]; n_A--; n_C++; n_An_Bn_C Viene restituito il controllo
123
Un esempio hanoi(2,A,N_a,B,N_b,C, N_c); A B through C Viene restituito il controllo a questa chiamata 4 3 2 1 301 n_An_Bn_C b[n_B]=a[n_A-1]; n_A--; n_B++;
124
Un esempio hanoi(2,A,N_a,B,N_b,C, N_c); A B through C Si invoca: hanoi (1, C, N_c, B, N_b, A, N_a); C B through A 4 3 2 1 211 n_An_Bn_C b[n_B]=a[n_A-1]; n_A--; n_B++;
125
Un esempio hanoi(1,C,N_c,B,N_b,A, N_a); C B through A 4 3 2 1 211 n_An_Bn_C
126
Un esempio hanoi(1,C,N_c,B,N_b,A, N_a); C B through A 4 3 2 1 220 n_An_Bn_C Si restituisce il controllo al chiamante
127
Un esempio hanoi(2,A,N_a,B,N_b,C, N_c); A B through C 4 3 2 1 220 n_An_Bn_C hanoi (2,------------------) ha terminato le istruzioni da eseguire. Restituisce il controllo al chiamante
128
Un esempio hanoi(3,A,N_a,C,N_c,B, N_b); A C through B Aveva invocato: hanoi (2, A, N_a, B, N_b, C, N_c); A B through C Questa invocazione ha ora ritornato Il controllo 4 3 2 1 220 n_An_Bn_C
129
Un esempio hanoi(3,A,N_a,C,N_c,B, N_b); A C through B 4 3 2 1 220 n_An_Bn_C Si esegue: c[n_C]=a[n_A-1]; n_A--; n_C++;
130
Un esempio hanoi(3,A,N_a,C,N_c,B, N_b); A C through B 4 3 2 1 121 n_An_Bn_C Si esegue: c[n_C]=a[n_A-1]; n_A--; n_C++;
131
Un esempio hanoi(3,A,N_a,C,N_c,B, N_b); A C through B 4 3 2 1 121 n_An_Bn_C Si esegue: c[n_C]=a[n_A-1]; n_A--; n_C++; Si invoca: hanoi (2, B, N_b, C, N_c, A, N_a); B C through A
132
Un esempio hanoi(2,B,N_b,C,N_c,A, N_a); B C through A 4 3 2 1 121 n_An_Bn_C Si invoca: hanoi (1, B, N_b, A, N_a, C, N_c); B A through C
133
Un esempio hanoi(1,B,N_b,A,N_a,C, N_C); B A through C 4 3 2 1 121 n_An_Bn_C
134
Un esempio hanoi(1,B,N_b,A,N_a,C, N_C); B A through C 4 3 2 1 211 n_An_Bn_C Si restituisce il controllo al chiamante
135
Un esempio hanoi(2,B,N_b,C,N_c,A, N_a); B C through A Aveva invocato: hanoi (1, B, N_b, A, N_a, C, N_c); B A through C Tale invocazione ha terminato restituendo il controllo 4 3 2 1 211 n_An_Bn_C Si esegue: c[n_C]=b[n_A-1]; n_B--; n_C++;
136
Un esempio hanoi(2,B,N_b,C,N_c,A, N_a); B C through A 4 3 2 1 202 n_An_Bn_C Si esegue: c[n_C]=b[n_B-1]; n_B--; n_C++; Si invoca: hanoi (1, A, N_a, C, N_c, B, N_b); A C through B
137
Un esempio hanoi(1,A,N_a,C,N_c,B, N_c); A C through B 4 3 2 1 202 n_An_Bn_C
138
Un esempio hanoi(1,A,N_a,C,N_c,B, N_c); A C through B 4 3 2 1 103 n_An_Bn_C Si restituisce il controllo al chiamante
139
Un esempio B C through A 4 3 2 1 103 n_An_Bn_C Si restituisce il controllo al chiamante hanoi(2,B,N_b,C,N_c,A, N_a);
140
Un esempio A C through B 4 3 2 1 103 n_An_Bn_C Si restituisce il controllo al chiamante hanoi(3,A,N_a,C,N_c,B, N_b);
141
Un esempio A B through C 4 3 2 1 103 n_An_Bn_C hanoi(4,A,&n_A,B,&n_B,C, &n_C); Si esegue: b[n_B]=a[n_A-1]; n_B++; n_A--;
142
Un esempio A B through C 4 3 2 1 013 n_An_Bn_C hanoi(4,A,&n_A,B,&n_B,C, &n_C); Si esegue: b[n_B]=a[n_A-1]; n_B++; n_A--; Si invoca hanoi(3,C,N_c,B,N_b,A,N_a);
143
Un esempio C B through A 4 3 2 1 013 n_An_Bn_C hanoi(3,C,N_c,B,N_b,A,N_a); Si invoca hanoi(2,C,N_c,A,N_a,B,N_b);
144
Un esempio C A through B 4 3 2 1 013 n_An_Bn_C hanoi(2,C,N_c,A,N_a,B,N_b); Si invoca hanoi(1,C,N_c,B,N_b,A,N_a);
145
Un esempio C B through A 4 3 2 1 013 n_An_Bn_C hanoi(1,C,N_c,B,N_b,A,N_a);
146
Un esempio C B through A 4 3 2 1 022 n_An_Bn_C hanoi(1,C,N_c,B,N_b,A,N_a); Si restituisce il controllo al chiamante
147
Un esempio C A through B 4 3 2 1 022 n_An_Bn_C hanoi(2,C,N_c,A,N_a,B,N_b); Si esegue: a[n_A]=c[n_C-1]; n_A++; n_C--;
148
Un esempio C A through B 4 3 2 1 121 n_An_Bn_C hanoi(2,C,N_c,A,N_a,B,N_b); Si esegue: a[n_A]=c[n_C-1]; n_A++; n_C--; Si invoca hanoi(1,B,N_b,A,N_a,C,N_c);
149
Un esempio B A through C 4 3 2 1 121 n_An_Bn_C hanoi(1,B,N_b,A,N_a,C,N_c);
150
Un esempio B A through C 4 3 2 1 211 n_An_Bn_C hanoi(1,B,N_b,A,N_a,C,N_c); Si restituisce il controllo al chiamante
151
Un esempio C A through B 4 3 2 1 211 n_An_Bn_C Si restituisce il controllo al chiamante hanoi(2,C,N_c,A,N_a,B,N_b);
152
Un esempio 4 3 2 1 211 n_An_Bn_C C B through A hanoi(3,C,N_c,B,N_b,A,N_a); Si esegue: b[n_C]=c[n_C-1]; n_B++; n_C--;
153
Un esempio 4 3 2 1 220 n_An_Bn_C C B through A hanoi(3,C,N_c,B,N_b,A,N_a); Si esegue: b[n_C]=c[n_C-1]; n_B++; n_C--; Si invoca hanoi(2,A,N_a,B,N_b,C,N_c);
154
Un esempio 4 3 2 1 220 n_An_Bn_C A B through C hanoi(2,A,N_a,B,N_b,C,N_c); Si invoca hanoi(1,A,N_a,C,N_c,B,N_b);
155
Un esempio 4 3 2 1 220 n_An_Bn_C A C through B hanoi(1,A,N_a,C,N_c,B,N_b);
156
Un esempio 4 3 2 1 121 n_An_Bn_C A C through B hanoi(1,A,N_a,C,N_c,B,N_b); Si restituisce il controllo al chiamante
157
Un esempio 4 3 2 1 121 n_An_Bn_C A B through C hanoi(2,A,N_a,B,N_b,C,N_c); Si esegue: b[n_C]=a[n_C-1]; n_B++; n_A--;
158
Un esempio 4 3 2 1 031 n_An_Bn_C A B through C hanoi(2,A,N_a,B,N_b,C,N_c); Si esegue: b[n_C]=a[n_C-1]; n_B++; n_A--; Si invoca: hanoi(1,C,N_c,B,N_b,A,N_a);
159
Un esempio 4 3 2 1 031 n_An_Bn_C C B through A hanoi(1,C,N_c,B,N_b,A,N_a);
160
Un esempio 4 3 2 1 040 n_An_Bn_C C B through A hanoi(1,C,N_c,B,N_b,A,N_a); Si restituisce il controllo al chiamante
161
Un esempio 4 3 2 1 040 n_An_Bn_C Si restituisce il controllo al chiamante A B through C hanoi(2,A,N_a,B,N_b,C,N_c);
162
Un esempio 4 3 2 1 040 n_An_Bn_C Si restituisce il controllo al chiamante C B through A hanoi(3,C,N_c,B,N_b,A,N_a);
163
Un esempio 4 3 2 1 040 n_An_Bn_C Si restituisce il controllo al main Abbiamo correttamente spostato i dischi dal primo al secondo piolo A B through C hanoi(4,A,&n_A,B,&n_B,C, &n_C);
164
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007
165
Ricorsione e vettori Si scriva una funzione ricorsiva somma_v che dato un vettore di interi vett produca in output la somma degli elementi di vett
166
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Ricorsione e vettori Si scriva una funzione ricorsiva somma_v che dato un vettore di interi vett produca in output la somma degli elementi di vett –Se il vettore ha un unico elemento allora la somma dei suoi elementi è pari al valore dellelemento –Altrimenti la somma dei primi n elementi è pari al valore delln-esimo elemento + la somma dei primi n-1 elementi 032…9 vett Tale somma è ottenuta tramite chiamata ricorsiva
167
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Somma degli elementi di un vettore /*pre: il vettore ha almeno un elemento*/ int somma_v(int vett[ ], int n) { if (n==1) return (vett[0]); else return (vett[n-1]+somma_v(vett,n-1)); }
168
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Ricerca di un elemento in un vettore Si scriva una funzione ricorsiva search_v che dato un vettore di interi vett ed un intero key determini se lelemento key è presente tra gli elementi del vettore –Se il vettore ha un unico elemento allora la funzione restituisce 1 se lelemento del vettore ha valore pari a key, 0 altrimenti –Altrimenti la funzione restituisce 1 se e solo se O lelemento key è contenuto nellultimo elemento del vettore OPPURE è contenuto nei primi n-1 elementi del vettore 032…9 vett Tale verifica è effettuata tramite chiamata ricorsiva key=3
169
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Ricerca di un elemento in un vettore /*pre: il vettore ha almeno un elemento*/ int search_v(int vett[ ], int n, int key) { if (n==1) return (vett[0]==key); else return ((vett[n-1]==key)|| (search_v(vett,n-1,key))); (search_v(vett,n-1,key)));}
170
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Minimo in un vettore Si scriva una funzione ricorsiva min_v che dato un vettore di interi vett determini il valore dellelemento più piccolo del vettore –Se il vettore ha un unico elemento allora la funzione restituisce il valore dellelemento –Altrimenti si calcola il valore più piccolo tra i primi n-1 elementi. Se tale valore è più piccolo delln-esimo elemento allora è il valore più piccolo del vettore. ALTRIMENTI il valore più piccolo del vettore è costituito dalln-esimo elemento del vettore 032…9 vettIl valore più piccolo tra i primi n-1 elementi è restituito dalla chiamata ricorsiva
171
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Minimo in un vettore /*pre: il vettore ha almeno un elemento*/ int min_v(int vett[ ], int n) { int temp; if (n==1) return (vett[0]); else{temp=min_v(vett,n-1); if (temp<vett[n-1]) return temp; else return (vett[n-1]); }}
172
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizi Esercizi su stringhe e caratteri – Versioni iterative –Versioni ricorsive ® per indicare una soluzione ricorsiva
173
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 1 Si scriva una procedura Iterativa che, dato un testo (di dimensione minore di max_size), stampi il testo invertito e senza gli spazi Si memorizza il testo –tranne gli spazi- in una stringa si stampano i caratteri della stringa (dallultimo al primo)
174
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 1-caratteri void elimina_spazi_e_inverti (int max_size) { int c,count,i; int c,count,i; char str[max_size]; char str[max_size]; count=0; count=0; while (((c=getchar()) != EOF) &&(count<max_size)) while (((c=getchar()) != EOF) &&(count<max_size)) { if (c!= ) if (c!= ) { str[count]=c; str[count]=c; count++; count++; } } str[count]=\0; str[count]=\0; for (i=count-1;i>=0;i- -) for (i=count-1;i>=0;i- -) printf(%c,str[i]); printf(%c,str[i]);} Si scriva una procedura Iterativa che, dato un testo (di dimensione minore di max_size), stampi il testo invertito e senza gli spazi
175
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 1, versione ricorsiva Si scriva una procedura ricorsiva che, dato un testo stampi il testo invertito e senza gli spazi Leggi il carattere corrente e memorizzalo in c Leggi il resto del testo stampandolo invertito e senza gli spazi Se c è diverso da uno spazio stampa c
176
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 1-caratteri ® void Relimina_spazi_e_inverti () { int c; int c; if ((c=getchar()) != EOF) if ((c=getchar()) != EOF) { Relimina_spazi_e_inverti(); Relimina_spazi_e_inverti(); if (c!= ) if (c!= ) putchar ( c); putchar ( c);}} Si scriva una procedura ricorsiva che, dato un testo stampa il testo invertito e senza gli spazi
177
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 1-stringhe /*stampa di una stringa */ void printstringa (char *); main(){ char str1[1024]; printf(inserisci stringa \n); scanf(%s,str1);printstringa(str1);………………………} /*Post: stampa il contenuto della stringa*/ void printstringa (char *s) { for (;*s!=\0;s++) putchar(*s); putchar(*s);} Si scriva una procedura iterativa che, data una stringa s presa in input ne stampi i caratteri in output OPPURE: void printstringa (char *s) { int i; for (i=0;s[i]!=\0;i++) putchar(s[i]); }
178
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 1-stringhe Si scriva una procedura ricorsiva che, data una stringa s presa in input ne stampi i caratteri in output Stampa lelemento corrente Stampa il resto degli elementi della stringa
179
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 1-stringhe ® /*stampa di una stringa (ricorsiva)*/ void Rprintstringa (char *); main(){ char str1[1024]; printf(inserisci stringa \n); scanf(%s,str1);Rprintstringa(str1);………………………} /*Post: stampa il contenuto della stringa*/ void Rprintstringa (char *s) { if (*s != '\0') {putchar(*s); Rprintstringa (s+1); }} Si scriva una procedura ricorsiva che, data una stringa s presa in input ne stampi i caratteri in output Attenzione: qui abbiamo usato laritmetica dei puntatori per chiamare la funzione ricorsiva sul resto della stringa, escluso lelemento corrente Come dovremmo modificare il codice per stampare i caratteri della stringa in ordine inverso?
180
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 2-stringhe Si scriva una procedura ricorsiva che, data una stringa s presa in input ne stampi i caratteri in output in ordine inverso Memorizza lelemento corrente in c Stampa il resto degli elementi della stringa in ordine inverso Stampa quanto memorizzato in c
181
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 2-stringhe ® /*stampa di una stringa (ricorsiva)*/ void Rprintstringa_invertita (char *); main(){ char str1[1024]; printf(inserisci stringa \n); scanf(%s,str1);Rprintstringa_invertita(str1);………………………} /*Post: stampa il contenuto della stringa invertito*/ void Rprintstringa_invertita (char *s) { if (*s != '\0') { Rprintstringa_invertita(s+1); Rprintstringa_invertita(s+1); putchar(*s); putchar(*s); }} Si scriva una procedura ricorsiva che, data una stringa s presa in input ne stampi i caratteri in output in ordine invertito
182
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Cosa succede in memoria… Allentrata nella funzione si alloca memoria per il puntatore s che punta al primo elemento della stringa corrente Non siamo arrivati al carattere di fine stringa quindi si invoca la chiamata ricorsiva void Rprintstringa_invertita (char *s) { if (*s != '\0') { Rprintstringa_invertita(s+1); Rprintstringa_invertita(s+1); putchar(*s); putchar(*s); }} blue\0 7200 s Linvocazione della chiamata ricorsiva farà stampare in ordine inverso il resto della stringa a partire dal secondo carattere (s+1) è la locazione di memoria dove è memorizzato il secondo carattere della stringa eul
183
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Cosa succede in memoria… Allentrata nella funzione si alloca memoria per il puntatore s che punta al primo elemento della stringa corrente Non siamo arrivati al carattere di fine stringa quindi si invoca la chiamata ricorsiva void Rprintstringa_invertita (char *s) { if (*s != '\0') { Rprintstringa_invertita(s+1); Rprintstringa_invertita(s+1); putchar(*s); putchar(*s); }} blue\0 7200 s Linvocazione della chiamata ricorsiva farà stampare in ordine inverso il resto della stringa a partire dal secondo carattere (s+1) è la locazione di memoria dove è memorizzato il secondo carattere della stringa eul Basterà quindi stampare il carattere puntato da s eulb
184
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esercizio 3-stringhe /*calcola la lunghezza di una stringa */ int String_length(char *); main(){ char str1[1024]; printf(inserisci una stringa \n); scanf(%s,str1); printf(la lunghezza della stringa e %d \n, String_length(str1)); ………………………} /*calcola la lunghezza della stringa*/ int String_length(char *s1) { int count=0: int count=0: while (*s1 != \0) { count++; count++; s1++; s1++; } return count; } Si scriva una funzione iterativa che, data una stringa ne calcoli il numero di caratteri (escluso il carattere di fine stringa)
185
Esercizio 3-stringhe ® /*calcola il numero di caratteri in una stringa*/ int Rsizestringa (char *, int); main(){ char str1[1024]; printf(inserisci stringa \n); scanf(%s,str1); printf(il numero di caratteri della stringa e %d \n, Rsizestringa(str1,0) ); ………………………} /*calcola il numero di caratteri in una stringa*/ /*Pre: s stringa, i>=0, chiamato con i==0 */ /*Post: restituisce il numero di caratteri della stringa (escluso il carattere di fine stringa */ int Rsizestringa(char s[ ], int i) {if(s[i]=='\0') return 0; else return (1+Rsizestringa(s,i+1)); } Si scriva una procedura ricorsiva che, data una stringa s presa in input calcoli il numero di caratteri della stringa (escluso il carattere di fine stringa) OPPURE: int Rsizestringa (char *s) { if (*s == '\0') return 0; else return (1+Rsizestringa(s+1)); }
186
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Manipolazione di reali in C I numeri reali sono rappresentati in binario nel computer 1/10=0.1 è rappresentato nella forma frazionaria binaria come 0.0001100110011001100110011001100110 011001100110011... La rappresentazione dei reali è binaria. Alcuni numeri che ci Sembrerebbero perfettamente rappresentabili hanno dei problemi di rappresentazione in binario.
187
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Manipolazione di reali in C Ragionando in base 10 è facile comprendere un problema: Consideriamo la frazione 1/3 Corrisponde ad un numero periodico –0.333…. I numeri reali in una macchina sono memorizzati con un numero limitato di byte si perde in precisione nella rappresentazione I numeri reali in una macchina sono memorizzati con un numero limitato di byte si perde in precisione nella rappresentazione Il problema non riguarda solo i numero periodici! Il problema non riguarda solo i numero periodici!
188
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Errore nella rappresentazione dei reali Abbiamo un numero limitato di byte (es. 8) per rappresentare un double. Tra quanti numeri è possibile distinguere usando 8*8=64 bit?
189
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Errore nella rappresentazione dei reali Abbiamo un numero limitato di byte (es. 8) per rappresentare un double. Tra quanti numeri è possibile distinguere usando 8*8=64 bit? 2 64 2 64 2 64 Lintervallo dei reali rappresentati è quindi diviso in 2 64 sottointervallini Non possiamo avere una rappresentazione dellintervallo continuo dei numeri reali Se immaginate che il numero reale che si trova nel mezzo dellintervallo sia rappresentato con la sequenza di bit che è associata allintervallo, e che tutti gli altri valori che cadono nellintervallo siano approssimati con tale sequenza di bit lerrore massimo è q/2 con q ampiezza dei sottointervallini. cè un errore di rappresentazione maggiore il numero di bit minore lerrore di rappresentazione Che comunque non può essere totalmente annullato È un errore di rappresentazione che ci portiamo dietro e che può anche Accumularsi facendo operazioni sui reali
190
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esempio Nel caso di 0.1 La stampa del valore decimale dellapprossimazione binaria del numero fornisce il seguente risultato 0.10000000000000001 Non è un bug! Come abbiamo visto dipende dalla rappresentazione dei numeri reali
191
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Esempio Fare operazioni sui reali può portare a sorprese sum = 0.0 for (i=0;i<10;i++) sum += 0.1; sum += 0.1; Il valore di sum alluscita dal ciclo è: 0.99999999999999989 0.99999999999999989
192
In sintesi La rappresentazione dei reali porta ad approssimazioni, che possono accumularsi o bilanciarsi facendo operazioni sui reali – Non è un bug, è q.sa di intrinseco nella rappresentazione di un intervallo continuo in una macchina Cosa si può fare: – tenerne conto nello scrivere un programma (nessuna soluzione prefatta, criteri generali-vedi qui di seguito- e buon senso portano alla soluzione) – Ad esempio anziché testare se A=B nel caso in cui A e B siano diversi, testare se A e B sono pressochè uguali |A-B|<= epsilon (cercando così di filtrare problemi di rappresentazione che si ripercuotono tipicamente sulle cifre meno significative). –Esistono librerie a precisione infinita (o meglio a precisione arbitraria) libreria BigDigits Non sono a precisione infinita ma cercano di allocare dinamicamente maggiore o minore memoria per memorizzare i numeri reali in modo da aumentare laccuratezza con cui sono rappresentati Memorizzano in strutture dati a dimensione variabile i numeri reali Memorizzano in strutture dati a dimensione variabile i numeri reali Rallentano lesecuzione Rallentano lesecuzione
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.