Tecniche della Programmazione, lez.15 - Richiamo su (perche' serono molto da qui in poi) - scansione di ay con puntatori - Varie applicazioni dell uso di puntatori - Scansione e ricerca in ay - Riuso di una funzione su ay - Uso di puntatori per gestire parametri di output - Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori Cogito ergo sum: riflettere sulla differenza nell'uso dell'asterisco in int * pi; e *pi=3; nel primo caso si tratta di una definizione e l'asterisco e' usato per dire che stiamo definendo una ariabile puntatore; nel secondo caso stiamo usando una ariabile puntatore pi, per eseguire l'assegnazione di 3 nella locazione intera puntata da pi
Chiamata ed Attiazione di funzione 1/2 int mcd(int n, int m) { int risult; while (n!=m) if (m>n) m=m-n; else n-=m; risult = n; /* (o m ) */ return risult; #include <stdio.h> int main() { int primo, secondo; printf("numeri "); scanf("%d %d", &primo, &secondo); printf("mcd=%d\n", mcd(primo, secondo)); return 0; funzione mcd, PARAMETRI FORMALI: n, m VARIABILI LOCALI: risult VALORE RISULTATO di tipo int CHIAMATA di funzione, - PARAMETRI ATTUALI: primo, secondo ATTIVAZIONE 1) passaggio dei parametri: ATTUALI ---> FORMALI 2) esecuzione del codice della funzione 3) restituzione del risultato Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 2/20
Chiamata ed Attiazione di funzione 2/2 #include <stdio.h> int main() { int primo, secondo; printf("mcd=%d\n", mcd(primo, secondo)); return 0; CHIAMATA di funzione, - PARAMETRI ATTUALI: primo, secondo ATTIVAZIONE (alloc. ) 1) passaggio dei parametri: ATTUALI ---> FORMALI 2) esecuzione del codice della funzione nell' 3) restituzione del risultato e dealloc. int mcd(int n, int m) { int risult; return risult; primo secondo Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 3/20 5 Record di Attiazione: area di riserata per l'esecuzione di una chiamata mcd(primo, secondo) AREA PARAMETRI n RISULTATO 5 AREA VAR LOCALI risult m ALTRE AREE
Scansione ay in ari modi 1/ esercizio funzione che riceendo stampa #define N oid stampaarray1 (int [N]) { int i; for (i=0; i<n; i++) printf("componente %d = %d\n", i, [i]); return; int main() { int [N] = {; stampaarray1(); un ay () di N interi, (noto N come costante) stiamo passando un indirizzo stampaarray1() 2 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori /20 i PAR LOC
Scansione ay in ari modi 2/ come sopra, ma stampaarray2 e 3 hanno un parametro puntatore: dato che quel che si passa nella chiamata e' un puntatore, non c'e' problema. NB in stampaarray3 usiamo un puntatore come se fosse il nome di un ay oid stampaarray2 (int * ) { int i; for (i=0; i<n; i++) printf cosa? return; CHIAMATA: stampaarray2() [i] *(+i) stampaarray() PAR LOC i oid stampaarray3 (int * ) { int i; for (i=0; i<n; i++) [i] *(+i) printf notazione alternatia a quella sopra? return; CHIAMATA: stampaarray3() 2 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 5/20
Scansione ay in ari modi 2/ come sopra, ma stampaarray2 e 3 hanno un parametro puntatore: dato che quel che si passa nella chiamata e' un puntatore, non c'e' problema. NB in stampaarray3 usiamo un puntatore come se fosse il nome di un ay oid stampaarray2 (int * ) { int i; for (i=0; i<n; i++) printf("componente %d = %d\n", i, *(+i)); return; CHIAMATA: stampaarray2() stampaarray() PAR LOC i oid stampaarray3 (int * ) { int i; for (i=0; i<n; i++) printf("componente %d = %d\n", i, [i]); return; CHIAMATA: stampaarray3() [i] *(+i) 2 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori /20
Scansione ay in ari modi 3/ come sopra: ma stampaarray ricee un parametro di tipo ay e lo usa come se fosse un puntatore oid stampaarray (int [N]) { int i; stampaarray() PAR for (i=0; i<n; i++) printf("componente %d = %d\n", i, *(+i)); return; CHIAMATA: stampaarray() [i] *(+i) i LOC NB Le chiamate funzione() sembrano tutte uguali: prendono il medesimo parametro: A liello di tipi nei parametri delle funzioni int * e int [] sono equialenti 2 (discorso dierso se int * o int [N] fossero ariabili locali in una funzione ero? Perché??) Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori /20
Scansione ay in ari modi / come sopra: ora pero' la funzione usa un puntatore per scandire l'ay (e non piu' l'intero i) #define N oid stampaarraypunt (int *) { int *pi; pi punta dopo l ultima locazione stampaarraypunt() PAR for (pi= ; pi< ; pi++) printf(" - %d\n", *pi); return; pi punta sulla prima locazione pi LOC int main() { int [N] = {; stampaarraypunt(); 2 +N-1 +N Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 8/20
Scansione ay in ari modi / come sopra: ora pero' la funzione usa un puntatore per scandire l'ay (e non piu' l'intero i) #define N oid stampaarraypunt (int *) { int *pi; stampaarraypunt() PAR for (pi=; pi<+n; pi++) printf(" - %d\n", *pi); return; pi LOC int main() { int [N] = {; stampaarraypunt(); 2 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori /20 +N-1
Scansione ay in ari modi / come sopra: ora pero' la funzione usa un puntatore per scandire l'ay (e non piu' l'intero i) #define N oid stampaarraypunt (int *) { int *pi; for (pi=; pi<+n; pi++) printf(" - %d\n", *pi); return; &[N] stampaarraypunt() PAR LOC pi int main() { int [N] = {; stampaarraypunt(); 2 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 10/20 +N-1
Uso di Puntatori per scandire ay 1/2 esercizio funzione che riceendo un ay () di interi, la dimensione (n) di, e un intero (m) restituisca la somma dei primi m elementi di (o tutti se m>=n) /* 1a fase: ambiente di calcolo */ #define DIM (**) int main() { int [DIM]={; int quanti, sommaelem; quanti = ; sommaelem = sommaprimi(, DIM, quanti); printf(" %d ", sommaelem); return 0; /* scanf( %d, &quanti); */ /* 2a fase: PROTOTIPO (dichiarazione) (**) */ int sommaprimi (int *, int, int);, DIM, quanti sommaprimi(,, ); 2 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 11/20 n m + 0 + 1 +? +??
Uso di Puntatori per scandire ay 1/2 esercizio funzione che riceendo un ay () di interi, la dimensione (n) di, e un intero (m) restituisca la somma dei primi m elementi di (o tutti se m>=n) /* 1a fase: ambiente di calcolo */ #define DIM (**) int main() { int [DIM]={; int quanti, sommaelem; quanti = ; sommaelem = sommaprimi(, DIM, quanti); printf(" %d ", sommaelem); return 0; /* scanf( %d, &quanti); */ /* 2a fase: PROTOTIPO (dichiarazione) (**) */ int sommaprimi (int *, int, int);, DIM, quanti sommaprimi(,, ); 2 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 12/20 n m + 0 + 1 + 5 +
Uso di Puntatori per scandire ay 2/2 Il prototipo sere a DICHIARARE la funzione, in modo che il codice successio la conosca (cioè il compilatore sappia come preparare la chimata, conoscendo 1) il tipo del risultato della funzione, 2) il nome della funzione, e 3) i nomi e tipi dei parametri). Se la funzione e dichiarata, la sua effettia DEFINIZIONE puo essere ritardata a dopo quella della funzione chiamante. /* 3a fase: definizione funzione */ int sommaprimi (int *, int n, int m) { int i, somma=0; for (i=0; i<m; i++) somma += *(+i); return somma; if (m>n) m=n; a fase? Test m < n / m == n m > n / m < 0, DIM, quanti sommaprimi(,, ); Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori /20 n m 2 + 0 + 1 +? +??
Riuso di un modulo e gioco di puntatori esercizio dato un ay di elementi interi, stampare la somma A) dei primi 5 B) di quelli dal 2 o al 5 o /* 1a fase: ambiente di calcolo */ #define DIM int sommaprimi(int *, int, int); int main() { int [DIM]={; 2 + 0 + 1 2 + 3 + + /* A) */ printf("somma primi 5: %d\n", sommaprimi(, DIM, 5)); sottoay di elem /* B) nell'ay di indirizzo iniziale +1 e lunghezza (DIM-1) sommare i primi (5-1) */ printf("somma da sec a quinto: %d\n", sommaprimi(+1, DIM-1, 5-1)); return 0; Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 1/20
Ricerca in ay, mediante puntatori 1/3 esercizio funzione che riceendo un ay () di interi, la dimensione (n) di, e un intero (chi) restituisca il puntatore al 1 o elemento di che e' uguale a chi /* definizione della funzione */ int * troaelemento(int *, int n, int chi) { int *pi = ; /* NB init in def; sarebbe equi. fare while (pi!= +n) if (*pi == chi) return pi; else pi++; return NULL; int *pi; pi=; */ - quando pi == +n (+n), uol dire che poco prima pi puntaa sull'ultimo elem. e ora punta fuori dell'ay; - se si scopre che chi==*pi, pi e' l'ind. cercato e si esce restituendo pi; - se nessun elemento e' == chi, iati fuori dell'ay si rest. NULL Test - chi e' in ay (in mezzo)? - chi non c'e'? - chi c'e' al primo posto? - chi c'e' all'ultimo posto? troaelemento(,, ) + 0 + 1 + n-2 + n-1 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 15/20 PAR n chi 2 RISULT. LOC pi
Ricerca in ay, mediante puntatori 2/3 esercizio funzione che riceendo un ay () di interi, la dimensione (n) di, e un intero (chi) restituisca il puntatore alla ultima occorrenza di chi in (opp. NULL) /* 1a fase: ambiente di calcolo */ #define DIM int * troaultima (int *, int, int) int main() { int datroare=, [DIM]; int *pris; /* risultato */ /* lettura ay */ RISULT. troaultima(,, ) n chi pris = troaultima(, DIM, datroare); if (pris!= NULL) printf("troato %d\n", *pris); else printf("tsk tsk \n"); return 0; risultato e non 2 + 0 + 1 + n-2 + n-1 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 1/20
Ricerca in ay, mediante puntatori 3/3 esercizio ultima occorrenza /* definizione funzione */ int * troaultima (int *, int n, int chi) int *pr = NULL, /* risultato (se non cambia mai restituiremo NULL) */ *pi = ; /* per scandire ay */ while( pi < +n) { if (*pi == chi) pr = pi; pi++; return pr; un po' dierso dal caso precedente: qui quando troiamo "chi" (cioe' quando *pi == chi) dobbiamo -segnarci che all'indirizzo pi c'e' chi; -ma poi continuare a cercare chi (e quindi non si finisce qui, ma si incrementa comunque pi, in modo che alla prossima scansione si controllera' il prossimo elemento) -a meno che non sia finito l'ay (pi==+n) troaultima(,, ) Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 1/20 n chi 2 + 0 + 1 + n-2 + n-1 RISULT. pr pi
Uso di puntatori per PARAMETRI DI OUTPUT 1/ esercizio funzione che riceendo un ay () di interi, la dimensione (n) di, e un intero (chi) restituisca 1) puntatore alla ultima occorrenza di chi in (opp. NULL) due cose 2) numero di occorrenze di chi in (restituisce 2 risultati?!) un risultato (il primo) iene restituito dalla chiamata tramite return(come nell'esercizio precedente; l'altro risultato iene gestito come parametro di output: una ariabile passata alla funzione nella chiamata, che subisce modifiche (side effect - effetti collaterali) durante l'esecuzione della chiamata. ma non è esattamente così: iiamoci Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 18/20
Uso di puntatori per PARAMETRI DI OUTPUT 2/ esercizio Primo risultato: funzione che riceendo un ay () di interi, la dimensione (n) di, e un intero (chi) restituisca - puntatore alla ultima occorrenza di chi in (opp. NULL) - numero di occorrenze di chi in int main() { int datroare =, [DIM], numeroocc, *pris; pris = troaeconta(, DIM, datroare); /* modifica numeroocc)*/ pris?? numeroocc al momento della chiamata 2 troaeconta(, DIM, datroare) n chi Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 1/20
Uso di puntatori per PARAMETRI DI OUTPUT 2/ esercizio funzione che riceendo un ay () di interi, la dimensione (n) di, e un intero (chi) restituisca - puntatore alla ultima occorrenza di chi in (opp. NULL) - numero di occorrenze di chi in Primo risultato: oiamente OK what about the second? int main() { int datroare =, [DIM], numeroocc, *pris; pris = troaeconta(, DIM, datroare); /* modifica numeroocc)*/ pris? numeroocc al momento della chiamata 2 troaeconta(, DIM, datroare) n chi Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 20/20
Uso di puntatori per PARAMETRI DI OUTPUT 3/ esercizio funzione che riceendo un ay () di interi, la dimensione (n) di, e un intero (chi) restituisca - puntatore alla ultima occorrenza di chi in (opp. NULL) - numero di occorrenze di chi in Secondo risultato: int main() { int datroare =, [DIM], numeroocc, *pris; pris = troaeconta(, DIM, datroare); /* modifica numeroocc)*/ ariabili di proprietà della funzione chiamante - main() pris Tentatio ingenuo?? numeroocc al momento della chiamata 2 (tsk) una istruzione della funzione, che modifichi numeroocc e' illegale (la funzione non "ede" numeroocc). troaeconta(, DIM, datroare) n chi numeroocc = 2 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 21/20
Uso di puntatori per PARAMETRI DI OUTPUT / In qualche modo ci dee essere un parametro, collegato a numeroocc, che permetta di modificare numeroocc dall interno della funzione. int * troaeconta (int *, int n, int chi, int occorrenze) { (tsk, tsk ) int main() { int datroare =, [DIM], numeroocc, *pris; pris = troaeconta(, DIM, datroare, numeroocc); al momento della chiamata pris 2 troaeconta(, DIM, datroare, numeroocc) n? numeroocc chi occorrenze? 2 occorrenze = 2 Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 22/20
Uso di puntatori per PARAMETRI DI OUTPUT / In qualche modo ci dee essere un parametro, collegato a numeroocc, che permetta di modificare numeroocc dall interno della funzione. int * troaeconta (int *, int n, int chi, int occorrenze) { (tsk, tsk ) int main() { int datroare =, [DIM], numeroocc, *pris; pris = troaeconta(, DIM, datroare, numeroocc); dopo la chiamata pris 2? numeroocc Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 23/20
Uso di puntatori per PARAMETRI DI OUTPUT / In qualche modo ci dee essere un parametro, collegato a numeroocc, che permetta di modificare numeroocc dall interno della funzione. int main() { int datroare =, [DIM], numeroocc, *pris; pris = troaeconta(, DIM, datroare, numeroocc); al momento della chiamata (tsk, tsk ) pris? 2 troaeconta(, DIM, datroare, numeroocc) n pris? numeroocc? numeroocc 2 DOPO la chiamata Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 2/20 chi occorrenze = 2 ma occorrenze? 2 1) il parametro occorrenze corrisponde ad una locazione interna al (DIVERSA DALLA numeroocc della main() 2) il passaggio di un parametro e' "per alore" (QUI alore non definito!!) 3) occorrenze (parametro formale) iene modificata. La numeroocc della main() NO.
Uso di puntatori per PARAMETRI DI OUTPUT 5/! La soluzione, per gestire PARAMETRI DI OUTPUT, e' nell'uso della tecnica del PASSAGGIO DI INDIRIZZO: un escamotage per riuscire a ottenere effetti collaterali (indiretti ma effettii) con le funzioni C - non a passato numeroocc (cioe' il suo alore) - a passato &numeroocc, cioe' l'indirizzo della locazione - la funzione ricee l'indirizzo e usandolo riesce a modificare la ariabile esterna numeroocc al momento della chiamata pris? 2 troaeconta(, DIM, datroare, &numeroocc) n? numeroocc chi pocc *pocc = 2 con questa istruzione, eseguita nell'ambiente della funzione, iene modificata una locazione che appartiene ad un ambiente dierso Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 25/20
Uso di puntatori per PARAMETRI DI OUTPUT /!! /* definizione funzione */ int * troaeconta (int *, int n, int chi, int *pocc) int *pr = NULL, /* risultato (se non cambia mai restituiremo NULL */ *pi = ; /* per scandire ay */ *pocc = 0; /* contatore occorrenze NB da inizializzare!*/ while( pi < +n) { if (*pi == chi) { pr = pi; *pocc += 1; pi++; return pr; risultato pris Tecniche della Programmazione, M.Temperini, Lez. 15 - uso di puntatori 2/20? datroare? numeroocc 2 troaeconta(, DIM, datroare, &numeroocc) n chi pocc *pocc += 1 Dopo il passaggio indietro del risultato deallocazione del