Dipartimento di Elettronica ed Informazione Politecnico di Milano Informatica A - GES Prof. Plebani A.A. 2006/2007 Linguaggio C: puntatori La presente dispensa e da utilizzarsi ai soli fini didattici previa autorizzazione dell autore. E severamente vietata la riproduzione anche parziale e la vendita. 07/11/2006 Premessa Dichiarare una variabile significa riservare una zona di memoria composta da diverse celle Il numero di celle dipende dal tipo di dato (int 2 byte, float 4 byte, ) 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
Variabili e indirizzi int var; &var 3 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 Puntatore È 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 devo anche specificare che tipo di dato viene ospitato nella cella puntata Sintassi: Una variabile puntatore occupa solitamente 2 byte o 4 byte a seconda delle architetture
Significato &p 3 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 che contiene il puntatore Quello che caratterizza una variabile di tipo puntatore è il fatto che il suo valore è esso stesso un indirizzo di memoria Deferenziazione 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 *p=5; /* OK. *p è un intero */ p=5; /* errore. p è un puntatore */ Attenzione! Il simbolo * lo uso sia nella dichiarazione che nella deferenziazione
Valorizzazione di un puntatore Un puntatore non può assumere qualunque valore Essendo il suo valore un indirizzo di memoria deve puntare ad una zona ammessa Un programma può accedere solo alle celle di memoria di sua competenza Ad un puntatore è quindi possibile assegnare: L indirizzo di una variabile attraverso l operatore & Il valore null L indirizzo di una zona di memoria appositamente creata con la funzione malloc Indirizzo di una variabile A una variabile di tipo puntatore posso assegnare un indirizzo di memoria int x; &p &x x=5; p=&x; /* *p vale 5 */ 3 2 1 0 1 5 p x p punterà alla zona di memoria in cui è memorizzato il valore di x Ad una variabile puntatore non viene mai assegnato una costante
Valore NULL All atto della dichiarazione un puntatore punta a NULL; NULL è una parola chiave del C Indica una zona di memoria non significativa p p=null; malloc Nella libreria <mem.h> è definita la funzione malloc Riceve in ingresso la dimensione in byte della cella puntata Crea una zona di memoria nello heap Restituisce il puntatore alla zona di memoria creata p=malloc(sizeof(int)); *p=30; *p=30 Heap p Stack
Quando si usa La variabile puntatore è utile: Per il passaggio dei parametri tra sottoprogrammi Nella gestione delle strutture dati dinamiche (liste, alberi) Puntatore a tipi complessi: struct 1/2 È possibile dichiarare un puntatore anche a tipi di dati complessi come le struct typedef struct { char cognome[30]; char nome [30]; Data dati_anagrafici *p; data_di_nascita; char codice_fiscale [15]; } dati_anagrafici;
Puntatore a tipi complessi: struct 2/2 Accesso ai campi della struttura. Due notazioni equivalenti: (*p).data_di_nascita.giorno (*p).cognome[0] oppure p->data_di_nascita.giorno p->cognome[0] Effetti collaterali Quando due puntatori puntano alla stessa cella di memoria posso avere una modifica non voluta di variabili puntate int *p, *q; int x,y; p=&x; q=&y; *p=3; /*x vale 3*/ *q=5; /*y vale 5*/ p=q; /*p punta a Y*/ *q=7;/*anche p vale 7*/
Puntatori ed array I puntatori, in realtà, sono già stati utilizzati Dichiarare un array, infatti, significa dichiarare una variabile puntatore che punta al primo elemento dell array int vett[10]; vett è una variabile di tipo puntatore ad intero e il suo valore è la cella di memoria in cui è memorizzato vett[0] Copia di array Il fatto che dichiarare un array significhi in realtà dichiarare un puntatore spiega i problemi nella copia tra array int a[10], b[10]; a = b; a punterà al primo elemento dell array di b. Quindi non ho una copia ma due array che condividono gli stessi elementi La zona di memoria puntata da a prima dell assegnamento viene persa
Aritmetica degli indirizzi int i; int vett[10]; vett si comporta come un puntatore fisso vett[i] equivale a *(vett+i) *(p+i) equivale a p[i] p=vett equivale a p=&vett[0] p=vett+i equivale a p=&vett[i] (p+i) - (p+j) = valore intero pari al numero di elementi (interi) tra i e j