PuntatoriCorso di Fondamenti di InformaticaIngegneria delle Comunicazioni – BCORIngegneria Elettronica – BELR
Unità 6
Domenico Daniele Bloisi
Docenti
Parte I – prof. Silvio [email protected]@dis.uniroma1.it
http://www.dis.uniroma1.it/~salza/fondamenti.htm
Parte II – ing . Domenico Daniele Bloisi, [email protected]
http://www.dis.uniroma1.it/ ~bloisi /didattica /fondinf1112.htmlhttp://www.dis.uniroma1.it/ ~bloisi /didattica /fondinf1112.html
Nota: %7E corrisponde alla tilde ~
2011/2012RicorsioneUnità 6
Pagina 2
Informazioni Generali
ing. Domenico Daniele Bloisi, PhD
Dipartimento di Informatica e SistemisticaVia Ariosto 25Via Ariosto 25(adiacente Piazza Dante,
A fermate Manzoni, Vittorio Emanuele,Tram 3 fermata via Labicana)
mailto:[email protected]
http://www.dis.uniroma1.it/~bloisi
2011/2012PuntatoriUnità 6
Pagina 3
Ricevimento
Su appuntamento. Inviare una email per conferma.
DIS, via Ariosto 25DIS, via Ariosto 25II piano, stanza B211
Si consiglia di controllare la bacheca degli avvisihttp://www.dis.uniroma1.it/~bloisi/didattica/fondin f1112.html#Avvisi
2011/2012PuntatoriUnità 6
Pagina 4
Sommario – Unità 6
• Memoria, indirizzamento e puntatori• Tipo void * e conversioni sui puntatori• Gestione dinamica della memoria• Gestione dinamica della memoria• Tempo di vita delle variabili allocate dinamicamente
• Problemi di deallocazione della memoria• Passaggio dei parametri tramite puntatori
Pagina 52011/2012PuntatoriUnità 6
Memoria, indirizzamento e puntatori
L’accesso memoria di un calcolatore avviene attraverso un meccanismo di indirizzamento.
In C il programmatore ha la possibilità di gestire gli indirizzi attraverso delle variabili che vengono definite di tipo puntatore .
I valori delle variabili di tipo puntatore sono
Pagina 62011/2012PuntatoriUnità 6
I valori delle variabili di tipo puntatore sono indirizzi di memoria , ossia dei valori numerici che fanno riferimento a specifiche locazioni di memoria.
Notazione grafica
L’indirizzamento si rappresenta graficamente tramite una freccia.
Pagina 72011/2012PuntatoriUnità 6
Spesso non occorre conoscere lo specifico valore di una variabile di tipo puntatore (es. 00100).
Operatore indirizzo-di
Per ottenere dei valori di tipo puntatore, cioè degli indirizzi, si utilizza l’operatore &
int i = 1;printf("L\' indirizzo di i e\' "
"%p\n", &i);printf("mentre il valore di i e\' "
"%d\n", i);
stampa
Pagina 82011/2012
stampa
L' indirizzo di i e' 0028FF1Cmentre il valore di i e' 1
PuntatoriUnità 6
Operatore indirizzo-di
L’operatore & si chiama operatore indirizzo-di e restituisce l’indirizzo della variabile a cui viene applicato.applicato.
Nota:i = &10;non è ammesso dato che 10 è una costante int . Analogamente non si può accedere all’indirizzo di una espressione.
Pagina 92011/2012PuntatoriUnità 6
Nota: l’indicatore di conversione per un indirizzo è %p (il formato è definito dall’implementazione)
una espressione.
Operatore di dereferenziamento (indirizzamento indiretto)Quando si considera una variabile di tipo puntatore , l’operatore * permette di recuperare il valore della locazione di memoria puntata.locazione di memoria puntata.
int i, j = 1;i = *&j;
L’istruzione i = *&j; assegna (con una notazione un po’ complicata) il valore della variabile j alla variabile i . Equivale, in pratica, all’istruzione i = j;
Pagina 102011/2012
Equivale, in pratica, all’istruzione i = j;
PuntatoriUnità 6
L’operatore (unario) di indirizzamento indiretto * no n deve essere confuso con l’operatore di moltiplicazio ne (binario).
Operatore di dereferenziamento (indirizzamento indiretto)int i, j = 1;
00100 00200
i = *&j;
?i 1j
&j ≡ 00200
Valore contenuto in 00200 ≡ 1*( &j ) ≡
Pagina 112011/2012PuntatoriUnità 6
Valore contenuto in 00200 ≡ 1*( &j ) ≡
1i
00100
1j
00200
Operatore & VS operatore *
Se x è una variabile, &x denota l’indirizzo in memoria di tale variabile.
&x ≡ α&x ≡ α
x
αnome
indirizzo
Pagina 122011/2012PuntatoriUnità 6
Se α è l’indirizzo in memoria di una variabile, * α denota tale variabile:
* α ≡ x
Variabili di tipo puntatore
Per la gestione degli indirizzi occorre dichiarare de lle variabili di tipo puntatore, specificando il tipo d ella locazione di memoria puntata.locazione di memoria puntata.
int *p1;... // allocazione di memoria (vedi dopo)*p1 = 10;
dichiara una variabile di tipo puntatore ad intero ed
Pagina 132011/2012
dichiara una variabile di tipo puntatore ad intero ed assegna alla variabile puntata il valore 10.
PuntatoriUnità 6
Attenzione
1. La dichiarazione di una variabile puntatore non alloca memoria per la variabile puntata ;prima di accedere alla variabile puntata prima di accedere alla variabile puntata bisogna allocare esplicitamente memoria(vedremo dopo come …)
2. Nelle dichiarazioni multiple tipo:
int *p1, p2;
Pagina 142011/2012
int *p1, p2;
p2 non è un puntatore!
PuntatoriUnità 6
Esempio: uso di variabili puntatore
int i, j, k;int *pt_i, *pt_j;pt_i = &i;pt_i = &i;pt_j = &j;i = 1;j = 2;k = *pt_i + *pt_j;*pt_i = 10;printf("i = %d \ n", i);
Pagina 152011/2012
printf("i = %d \ n", i);printf("k = %d\n", k);
PuntatoriUnità 6
Diagramma della memoria
Le variabili di tipo int i , j , k , vengono manipolateattraverso i puntatori alle locazioni di memoria ad esse associate al momento della dichiarazione.associate al momento della dichiarazione.
Pagina 162011/2012PuntatoriUnità 6
Assegnazione di un valore specifico a puntatore#include <stdio.h>
int main () {
Output del compilatore
int main () {int *ptr;ptr = 1000;*ptr = 5;printf("%d\n", *ptr);
}
Cosa stampa questo codice?
Pagina 182011/2012PuntatoriUnità 6
Output del compilatore
warning: assignment makes pointer from integer without a cast
L’ assegnazione di un indirizzo specifico ad una variabile puntatore è da evitare poiché
Assegnazione di un valore specifico a puntatore
una variabile puntatore è da evitare poiché può causare il crash del programma.
Pagina 192011/2012PuntatoriUnità 6
Accessi in memoria
int i, j = 2, *pt;pt = &j;i = *pt;i = *pt;
per ottenere il valore da assegnare a i devono essere fatti 2 accessi in memoria:
• il primo accesso viene fatto all’indirizzo di pt , per recuperare il dato ivi memorizzato, i.e. l’indirizzo di j
Pagina 202011/2012
• il secondo accesso avviene all’indirizzo di j , per recuperare il valore memorizzato nella variabile j
PuntatoriUnità 6
Esempio puntatoriConsideriamo gli effetti del seguente codice:
int *pointer; // dichiara pointer come un // puntatore a int// puntatore a int
int x = 1, y = 2;pointer = &x; // (1) assegna a pointer l'indirizzo
// di x (i.e., pointer punta x)y = *pointer; // (2) assegna a y il contenuto di
// pointerx = pointer; // (3) assegna ad x l'indirizzo
Pagina 212011/2012PuntatoriUnità 6
x = pointer; // (3) assegna ad x l'indirizzo // contenuto in pointer
*pointer = 3; // (4) assegna alla variabile // puntata da pointer il valore 3
Diagramma della memoria
1x32456
1x32456
?
2y
pointer
54327
12098
(1)
32456
2y
pointer
54327
12098pointer = &x;
Pagina 222011/2012PuntatoriUnità 6
?pointer 32456pointer
Diagramma della memoria
1x32456
1x32456
32456
2y
pointer
54327
12098
(2)
32456
1y
pointer
54327
12098y = *pointer;
Pagina 232011/2012PuntatoriUnità 6
32456pointer 32456pointer
Diagramma della memoria
1x32456
32456x32456
32456
1y
pointer
54327
12098
(3)
32456
1y
pointer
54327
12098x = pointer;
Pagina 242011/2012PuntatoriUnità 6
32456pointer 32456pointer
Diagramma della memoria
32456x32456
3x32456
32456
1y
pointer
54327
12098
(4)
32456
1y
pointer
54327
12098*pointer = 3;
Pagina 252011/2012PuntatoriUnità 6
32456pointer 32456pointer
Ricapitolando
Possibili valori ottenibili tramite l’utilizzo di variabili puntatore:
pointer valore della variabile puntatore (i.e., l’indirizzo della locazione di memoria a cui punta)
&pointer indirizzo fisico della locazione di memoria del puntatore
Pagina 26
*pointer valore contenuto nella locazione di memoria a cui punta il puntatore
PuntatoriUnità 6
2011/2012
Operazioni sui puntatori
A valori di tipo puntatore si applicano le operazion i del tipo int .Particolarmente utile è l’operazione di incrementoParticolarmente utile è l’operazione di incremento
int *pti;...pt++;
che consente di puntare alla successiva locazione di tipo int .
Pagina 272011/2012
tipo int .
L’uso di queste operazioni verrà approfondito nella Unità 7 – Array e Matrici
PuntatoriUnità 6
Puntatori costanti
La specifica const può essere applicata anche a variabili di tipo puntatore.
double pi = 3.5;double const *pt = &pi ;(*pt )++; // OK (pi vale 4.5)pt++; // NO (pt e’ costante)
Pagina 282011/2012
In questo caso, la specifica const si applica al puntatore, ma non alla variabile puntata.
PuntatoriUnità 6
Puntatori a costanti
Si può anche specificare che un puntatore debba puntare a costanti.
const int k = 3;const int k = 3;const int *pt; // dichiarazione di puntatore
// a costantept = &k; // OKpt++; // ammesso anche se non si sa cosa
// vada a puntare ptint *pti ;
Pagina 292011/2012
int *pti ;pti = &k; // NO
PuntatoriUnità 6
Puntatori a puntatori
Come per ogni altro tipo si può definire un puntato re ad una variabile di tipo puntatore.
double x;double x;double * pt;double ** ptpt;x = 4;pt = &x;ptpt = &pt;printf("%f \ n", **ptpt);
Cosa stampa questo frammento di codice?
Pagina 302011/2012PuntatoriUnità 6
printf("%f \ n", **ptpt);
Il puntatore NULL (1/3)
Le variabili di tipo puntatore possono assumere anc he un valore speciale: NULL
Questo valore serve a specificare che la variabile non punta alcuna locazione di memoria .
In C tale valore in genere corrisponde allo 0, ma s i raccomanda di usare NULL , in particolare per verificare che ad una variabile puntatore non sia associato un o specifico riferimento.
Pagina 322011/2012
specifico riferimento.
PuntatoriUnità 6
NULL è una costante simbolica in genere definita in <stdio.h>
Il puntatore NULL (2/3)
Si faccia attenzione a non confondere variabili il cui valore è NULL con variabili non inizializzate:inizializzate:
una variabile non inizializzata non ha alcun valore, neanche NULL.
Il confronto con NULL può essere usato in una condizione di un’istruzione if - else , for , etc.
Pagina 332011/2012
condizione di un’istruzione if - else , for , etc.
PuntatoriUnità 6
Il puntatore NULL (3/3)
Esempio
int *pt = NULL;if (pt != NULL)if (pt != NULL)
*pt = 10;
In questo caso il ramo if non viene eseguito.
L’istruzione *pt = 10; eseguita al momentoin cui pt vale NULL genererebbe un errore a tempo di
Pagina 342011/2012
in cui pt vale NULL genererebbe un errore a tempo di esecuzione.
PuntatoriUnità 6
Il tipo void* (1/2)
Mentre nel caso delle dichiarazioni dei tipi primiti vi è indispensabile definire il tipo della variabile per consentire al compilatore di allocare la memoria consentire al compilatore di allocare la memoria necessaria, nel caso dei puntatori, la memoria per il puntatore è fissa (corrisponde alla dimensione di un indirizzo di memoria) e quindi si può omettere la specifica del tipo della variabile puntata.
void *pt ;int i;
Pagina 352011/2012
int i;pt = &i ;
PuntatoriUnità 6
Il tipo void* (2/2)
In questi casi:
• non sono più ammesse le operazioni sui • non sono più ammesse le operazioni sui puntatori
• il puntatore assegnato ad una variabile void*non può essere assegnato ad una variabile di tipo puntatore (ad un tipo definito).
Pagina 362011/2012PuntatoriUnità 6
tipo puntatore (ad un tipo definito).
Conversioni su puntatori
Anche nel caso delle variabili di tipo puntatore so no possibili conversioni esplicite:
void * pt;int i;pt = &i;int * pti;pti = (int*)pt; // il valore viene convertito
// a puntatore a int
Pagina 372011/2012
Tuttavia, l’utilizzo delle conversioni sui puntatori è sconsigliato in quanto spesso provoca degli errori di programmazione.
PuntatoriUnità 6
Gestione dinamica della memoria
Nell’ Unità 5 è stato presentato il modello di allo cazione della memoria tramite stack , che si basa sulle regole di campo d’azione (definito staticamente , cioè al momento campo d’azione (definito staticamente , cioè al momento della compilazione).
Attraverso i puntatori, il C permette di utilizzare u n altro modello di allocazione della memoria, che consente d i definire la memoria dinamicamente , cioè al momento dell’ esecuzione del programma.
Pagina 382011/2012
Questa possibilità risulta particolarmente utile ed importante quando non sono note o prevedibili a pri orile dimensioni dei dati in ingresso ad un programma.
PuntatoriUnità 6
L’operatore sizeof (1/2)
Il numero di byte occupati da una variabile è dato dall’applicazione di sizeof .
Esempio
sizeof(a) è il numero di byte occupati dalla variabile a
Pagina 392011/2012PuntatoriUnità 6
L’operatore sizeof può essere applicato ad un tipo, ad un nome di variabile o ad una costante
L’operatore sizeof (2/2)
Restituisce la dimensione in byte dell’oggetto passato come parametro
• tale calcolo viene effettuato in compilazione in base al tipo di dato che viene passato a sizeof
• se si incrementa un puntatore p, il suo valore numerico
Pagina 402011/2012
• se si incrementa un puntatore p, il suo valore numerico (indirizzo in memoria in byte) verrà incrementato di sizeof(*p)
PuntatoriUnità 6
stampa indirizzo, occupazione di memoria e valore
int main (void) {int a = 12;char b = 'a';char b = 'a';float c = 0.1243;printf ("Indirizzo di a e\' %x, occupa %d bytes,"
" il suo valore e\' %d\n", &a, sizeof(a), a);printf ("Indirizzo di b e\ ' %x, occupa %d bytes,"
" il suo valore e\' %c\n", &b, sizeof(b), b);printf ("Indirizzo di c e\' %x, occupa %d bytes,"
" il suo valore e \ ' %f \ n", &c, sizeof(c), c);
Pagina 412011/2012
" il suo valore e \ ' %f \ n", &c, sizeof(c), c);return 0;
}
PuntatoriUnità 6
%x intero esadecimale senza segno
Esecuzione
Esercizio 6.1Si modifichi il codice precedente in modo da stampa re la parola “byte” se l’occupazione è pari ad 1, mentre “byt es”
Pagina 422011/2012PuntatoriUnità 6
parola “byte” se l’occupazione è pari ad 1, mentre “byt es” se l’occupazione è > 1
Es. Indirizzo di b e' 28ff1b, occupa 1 byte, il suo valore e' a
Differenza tra valore e indirizzo di una variabile� L’indirizzo è dato in forma numerica (ma
non di tipo numerico) ed è assegnato dal compilatorecompilatore
� Il valore è assegnato dal programma
� Tutte le variabili dello stesso tipo occupano lo stesso numero di byte
Pagina 432011/2012PuntatoriUnità 6
stesso numero di byte• Hanno la medesima rappresentazione interna
Applicazione di sizeof (1/2)
Essendo un operatore , sizeof può essere utilizzatoponendo l’operando tra parentesi oppure anche senzal’utilizzo delle parentesil’utilizzo delle parentesi
Le seguenti istruzioni sono equivalenti tra loro:
char a = 'r';int size_a ;size_a = sizeof a;
Pagina 442011/2012
size_a = sizeof a;size_a = sizeof (a);
PuntatoriUnità 6
Applicazione di sizeof (2/2)
Un’eccezione a questa possibilità si ha nel caso seguente:
int size_float;
size_float = sizeof(float); // espressione // valida
size_float = sizeof float; // errore in // compilazione
Pagina 452011/2012
// compilazione
quando l’operando di sizeof è il nome di un tipo di dato(float , nell’esempio), le parentesi sono obbligatorie.
PuntatoriUnità 6
Allocazione dinamica della memoria
Durante l’esecuzione, un programma può richiedere esplicitamente uno spazio di memoria per immagazzinare dati.dati.Allo stesso modo, può richiedere di rilasciare tale spazio quando non sarà più necessario.
Il C offre la funzione malloc per riservare (allocare) uno spazio di memoria e la funzione free per rilasciare (deallocare) memoria.
Pagina 462011/2012
free per rilasciare (deallocare) memoria.
Insieme all’operatore sizeof sono essenziali per l’allocazione dinamica della memoria.
PuntatoriUnità 6
Funzione malloc
La funzione malloc permette di allocare dinamicamente una porzione (chunk) di memoria.
void *malloc( size_t size );
Restituisce un puntatore alla porzione di memoria di dimensione size oppure NULL se si è verificato un errore.E’ definita nella standard library - va inserita la direttiva#include <stdlib.h>
Pagina 472011/2012
#include <stdlib.h>
size_t è definito come il tipo intero senza segno restituito dall’operatore sizeof
PuntatoriUnità 6
Esempio malloc
int *p;• crea in memoria una variabile di tipo puntatore a int
p = malloc(sizeof(int));• crea in memoria una variabile di tipo int• restituisce l’indirizzo della variabile creata (prim o byte)• assegna l’indirizzo restituito a p
*p = 7;• la variabile di tipo int creata assume il valore 7
Pagina 482011/2012
• la variabile di tipo int creata assume il valore 7
printf("%d", *p);• viene stampato a video 7
PuntatoriUnità 6
Modello di allocazione dinamica
L’allocazione dinamica della memoria avviene nello heap.Se lo spazio di memoria allocabile dinamicamente è e saurito viene restituito il puntatore NULL.
int *pt1; // dichiarazione del puntatore ad intpt1 = malloc(sizeof(int)); // creazione dinamica
// della variabile intif (pt1 == NULL) {
printf("allocazione fallita\n");exit(EXIT_FAILURE);
}
Pagina 492011/2012
}
PuntatoriUnità 6
In caso di mancanza di memoria il programma termina con l’istruzione exit(EXIT_FAILURE); che notifica il fallimento.
Funzione free
La funzione free permette di deallocare la memoria allocata dinamicamente.
void free( void* ptr );
free dealloca lo spazio puntato da ptr , rendendolodisponibile per usi futuri.
Nota: ptr deve essere stato usato in una chiamata
Pagina 502011/2012
Nota: ptr deve essere stato usato in una chiamataprecedente a malloc()
E’ definita nella standard library ( <stdlib.h> )
PuntatoriUnità 6
Esempio free#include <stdio.h>#include <stdlib.h>
int main() {int main() {int *p;double *d;p = malloc(sizeof(int));*p = 7;printf("%d", *p);free(p);d = malloc(sizeof(double));
Pagina 512011/2012
d = malloc(sizeof(double));*d = 7;printf(" %f", *d);free(d);
}PuntatoriUnità 6
Esercizi
Esercizio 6.2
Scrivere un programma che legga 10 numeri interi e restituisca il minimo, usando variabili di tipo pun tatore restituisca il minimo, usando variabili di tipo pun tatore ad int anziché variabili di tipo int .
Esercizio 6.3
Scrivere il programma dell’esercizio precedente tram ite allocazione dinamica della memoria. Deallocare la memoria utilizzata prima della terminazione del
Pagina 522011/2012
memoria utilizzata prima della terminazione del programma.
PuntatoriUnità 6
Esercizi
Esercizio 6.4
Scrivere una funzione che dato in ingresso un puntatore ne stampi la dimensione in byte, il valor e, puntatore ne stampi la dimensione in byte, il valor e, l’indirizzo di memoria ed il valore della variabile puntata. Scrivere un programma che ne verifichi il comportamento.
Pagina 532011/2012PuntatoriUnità 6