DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Puntatori Marco D. Santambrogio – [email protected] Ver. aggiornata al 11 Marzo 2014 Immagini DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Struttura dati: typedef struct{ int R; int G; int B; } pixel pixel img[30][24]; Ma quanto è grossa immagine? pixel=(int*3) img= pixel*30*24 1 immagine= 2160 interi 2 Manipoliamo immagine DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • Problema: mettiamo a 0, tutti i pixel con rosso minore di 50 (soglia) void TagliaRossi(pixel immagine[30][24], int soglia); • Se volessimo scrivere una funzione che risolve il problema dato? Cosa ritorna? • NB: una immagine è un insieme di pixel, non un solo dato! Quali sono i parametri di ingresso? 3 RICORDIAMO: passaggio per valore DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Ambiente della funzione somma d1, d2 } Quando invoco la funzione in d1 e d2 vengono copiati i valori di valore1 e valore 2 /* nel main */ float valore1, valore2; float risultato; risultato=somma(valore1,valore2); valore1, valore2 risultato Quando la funzione termina il valore di risultato in somma viene copiato il risultato nel main risultato Ambiente della funzione main 4 Quindi…. DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void TagliaRossi(pixel immagine[30][24], int soglia); /* nel main */ pixel img[30][24]; int val_soglia; Ambiente della funzione TagliaRossi immagine[30][24] soglia img[30][24] val_soglia TagliaRossi(img[30][24], val_soglia); Quando invoco la funzione in immagine[30][24] vengono copiati i valori di img[30][24] Perchè? •Spreco di memoria: 2160 interi *2 •array1=array2 : VIETATO in C Ambiente della funzione main 5 Cosa ci piacerebbe? DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • Avere una sola copia del dato Non vogliamo sprecare spazio • Poter accedere a quella copia in maniera sicura Non vogliamo usare variabili globali! Sarebbe troppo alto il rischio di commettere errori! Invece che per copia, ci piacerebbe accedere tramite indirizzo 6 E quindi (veramente)… DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Sapendo dove si trova il primo punto aka: indirizzo primo pixel img[0][0] pixel img[30][24]; Con le dimensione della matrice: Righe: 30 Colonne: 24 Possiamo arrivare ad ogni punto (r,c)!!! Indirizzo di img[0][0] + r*Colonne + c &img[0][0] + r*Colonne + c 7 Obiettivi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • Puntatori 8 Variabili e indirizzi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE 3 int var; &var 2 var 1 0 • Supponiamo che la dichiarazione riservi la zona di memoria all’indirizzo 1 • var indica il contenuto della cella di memoria • &var indica l’indirizzo della cella di memoria 9 Puntatori – premessa DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • Dichiarare una variabile significa riservare una zona di memoria composta da diverse celle Il numero di celle dipende dal tipo di dato • Ogni cella di memoria ha un indirizzo fisico e: il nome della variabile indica il contenuto della cella di memoria l’operatore & permette di ottenere l’indirizzo di memoria della cella associata alla variabile cui l’operatore è applicato 10 Puntatore DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • È un tipo di dato che ammette tra i suoi valori un indirizzo di memoria La zona di memoria viene detta “puntata” dalla variabile puntatore La variabile puntatore viene detto che “punta” ad una cella di memoria • Quando dichiaro un puntatore si deve anche specificare che tipo di dato viene ospitato nella cella puntata Sintassi: int *p; 11 Significato DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE 3 int *p; &p 2 p 1 0 • p è una variabile come tutte le altre quindi p indica il contenuto della cella di memoria &p indica l’indirizzo di memoria • Quello che caratterizza una variabile di tipo puntatore è il fatto che il suo valore è esso stesso un indirizzo di memoria 12 Deferenziazione DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • Ad una variabile di tipo puntatore posso applicare l’operatore di deferenziazione * • *p indica il contenuto della cella puntata da p • Se p è un puntatore ad un intero allora *p è una semplice variabile intera int *p; *p=5; /* OK. *p è un intero */ p=5; /* errore. p è un puntatore */ • Attenzione! Il simbolo * lo uso sia nella dichiarazione che nella deferenziazione 13 Operazioni DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • A una variabile di tipo puntatore posso assegnare un indirizzo di memoria int x; int *p; &p 3 &x 2 x=5; p=&x; /* *p vale 5 */ 1 1 5 p x 0 • p punterà alla zona di memoria in cui è memorizzato il valore di x • Ad una variabile puntatore non viene mai assegnato una costante 14 Pointer Fun with Binky DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE This is document 104 in the Stanford CS Education Library. Please see http://cslibrary.stanford.edu/ for this and other free educational materials. Copyright Nick Parlante 1999. 15 Passaggio per INDIRIZZO DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • All’atto della chiamata l’indirizzo dei parametri attuali viene associato ai parametri formali il parametro attuale e il parametro formale si riferiscono alla stessa cella di memoria • Il sottoprogramma in esecuzione lavora nel suo ambiente sui parametri formali (e di conseguenza anche sui parametri attuali) ogni modifica sul parametro formale è una modifica del corrispondente parametro attuale • Gli effetti del sottoprogramma si manifestano nel chiamante con modifiche al suo ambiente locale di esecuzione 16 Passaggio parametri per indirizzo DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • Si utilizza: il costruttore di tipo puntatore per la definizione dei parametri formali della funzione float circonferenza(float *raggio) l’operatore di dereferenziazione all’interno della funzione circ = *raggio * 3.14; alla chiamata della funzione, si passa un indirizzo di variabile come parametro attuale c=circonferenza(&r); • Attenzione! Gli array sono SEMPRE passati per indirizzo. Una variabile di tipo array, infatti, è per definizione un puntatore 17 Esempio: passaggio per indirizzo DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE float circonferenza(float *raggio) { Ambiente della funzione float circ; circonferenza circ = *raggio * 3.14; *raggio = 7; /*istruzione senza circ raggio senso, voglio solo vedere cosa succede modificando il valore di un paramentro formale*/ return circ; Quando la funzione Quando invoco la funzione } /* nel main */ float c,r=5; c=circonferenza(&r); /*attenzione! D’ora in poi r vale 7 */ in raggio viene copiato l’indirizzo di r. Quindi *raggio e r sono la stessa cosa r termina il valore di circ in circonferenza viene copiato in c nel main c Ambiente della funzione main 18 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int p, int q) { int temp; a temp = p; 3 p = q; b 7 q = temp; } p 3 q 7 temp • Nel main: swap(a,b) 19 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int p, int q) { int temp; a temp = p; 3 p = q; b 7 q = temp; } p 3 q 7 temp 3 • Nel main: swap(a,b) 20 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int p, int q) { int temp; a temp = p; 3 p = q; b 7 q = temp; } p 7 q 7 temp 3 • Nel main: swap(a,b) 21 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int p, int q) { int temp; a temp = p; 3 p = q; b 7 q = temp; } p 7 q 3 temp 3 • Nel main: swap(a,b) 22 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int p, int q) { int temp; a temp = p; 3 p = q; b 7 q = temp; } Al termine dell’esecuzione di swap le variabili nel • Nel main: swap(a,b) main restano inalterate! p 7 q 3 temp 3 23 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int *p, int *q){ int temp; a temp = *p; 3 *p = *q; b 7 *q = temp; } p q temp • Nel main: swap(&a, &b) 24 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int *p, int *q){ int temp; a temp = *p; 3 b *p = *q; 7 *q = temp; } p q temp 3 • Nel main: swap(&a, &b) 25 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int *p, int *q){ int temp; a temp = *p; 7 *p = *q; b 7 *q = temp; } p q temp 3 • Nel main: swap(&a, &b) 26 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int *p, int *q){ int temp; a temp = *p; 7 *p = *q; b 3 *q = temp; } p q temp 3 • Nel main: swap(&a, &b) 27 Esempio: scambio di 2 valori interi DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE void swap (int *p, int *q){ int temp; a temp = *p; 7 *p = *q; b 3 *q = temp; } Al termine dell’esecuzione di swap le variabili nel • Nel main: swap(&a, main vengono modificate p q temp 3 &b) 28 scanf: stringhe Vs char DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE 29 Parametri di tipo array DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • Per usare in una funzione una variabile di tipo array occorre passare il suo indirizzo di base, perciò di fatto l’array è passato per locazione (indirizzo) • Una funzione C non restituirà un array (come contenuto), ma solo un puntatore a un array (cioè il suo nome come suo indirizzo)!! 30 Somma degli elementi di un array di int DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE 31 Somma degli elementi di un array di int: funzioni DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE 32 Somma degli elementi di un array di int: funzioni – con int *valori DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE 33 Parametri di tipo array DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • Due testate equivalenti: double mul(double *a, int n) double mul(double a[], int n) • N.B.: non c’è la dimensione, e n è la porzione occupata dell'array • Supponiamo di avere un array V[50]. Possibili chiamate: mul(V,50) restituisce V[0]*V[1]*…V[49] mul(V,30) restituisce V[0]*V[1]*…V[29] mul(&V[5],7) restituisce V[5]*V[6]*…V[11] mul(V+5,7) restituisce V[5]*V[6]*…V[11] 34 Fonti per lo studio + Credits DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE • Fonti per lo studio Binky Pointer Fun Video: http://cslibrary.stanford.edu/104/ • Credits Gianluca Palermo 35