Laboratorio di Linguaggi lezione VII: puntatori 3/3 Marco Tarini Università dellInsubria Facoltà...
-
Upload
fiammetta-valle -
Category
Documents
-
view
212 -
download
0
Transcript of Laboratorio di Linguaggi lezione VII: puntatori 3/3 Marco Tarini Università dellInsubria Facoltà...
Laboratorio di Linguaggi
lezione VII: puntatori 3/3
Marco Tarini
Università dell’Insubria
Facoltà di Scienze Matematiche, Fisiche e Naturali di Varese
Corso di Laurea in Informatica
Anno Accademico 2007/08
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Assegnare i Puntatori
• In memoria, un puntatore è un indirizzo– (...di una variabile)– (...di cui e' noto il tipo)
• Bene, ma quale indirizzo?
– Modo 1: prendere l'indirizzo di una variabile esistente• il puntatore punterà a quella variabile
– Modo 2: allocare (riservare, prenotare) della memoria libera
• il puntatore punterà ad una nuova variabile, memorizzata nella memoria così riservata
• la nuova variabile è allocata dinamicamente!
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Allocazione
void* malloc(unsigned int n);
funzione malloc ( sta per memory allocation )
1 - alloca n bytes di memoria.
2 - restituisce l' indirizzo della memoria appena allocata
• sotto forma di puntatore generico !
• " " puntatore generico, puntatore senza tipo, in pratica, un semplice indirizzo di memoria
void*
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Allocazione: esempio
int* p;p = malloc( ? );
Ma il tipo non torna!
A sx abbiamo un (int*) mentre a dx un (void*)
Avviene un Typecast fra puntatori
int* p;p = (int*) malloc(4);
Possiamo anche renderlo esplicito (meglio):
4
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Typecast fra puntatori
• Ogni tipo puntatore puo essere trasformato in un qualsiasi altro tipo di puntatore: (implicitamente o esplicitamente)
– da int* a double* , da void* a Persona*etc.
• Semantica: = “quello che fa”
– L’indirizzo rimane lo stesso, cambia l’interpretazione di ciò che ci trovo
– Nota: in effetti, a tempo di esecuzione, non avviene nulla!Cambiano solo cose nella testa del compilatore
• Costrutto estremamente POTENTE e di basso livello(e potenzialmente molto pacciugone)
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Typecast fra puntatori: primo esempio
int* p;p = malloc( 4 );
int* p;p = (int*) malloc(4);
Esplicito (meglio, più chiaro):
Implicito:
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Allocazione: e se la memoria finisce?
void* malloc(unsigned int n);
Se non c'è più memoria, l'allocazione "fallisce"
e malloc restituisce il valore speciale NULL• semanticamente, NULL è un "puntatore che non punta a nulla"• NULL è rappresentato dal valore 0
Quindi, il valore resituito dalle malloc va controllato !int* p;p = (int*) malloc(4);if (p == NULL) { /* finita memoria ... */}
oppure,più coincisamente
if (!p) {
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Allocazione
Il costrutto sizeof è estremamente utile con le malloc.
Usare sempre, anche con i tipi base• int, short, float, double...
• remember: il C non prescrive quanti bytes occupano!
typedef struct { /*blah blah... un sacco di campi, array...*/} TipoStrano TipoStrano* p;p = (TipoStrano *) malloc(sizeof(TipoStrano));
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Dellocazione
void free(void* p);
libera la memoria che era stata allocata all'indirizzo p.
Nota: p deve essere il risultato di una malloc!int* p;p = (int*) malloc(sizeof(int));... /* Qui uso (*p) */free(p);
se mi dimentico di deallocare, ho un cosiddetto memory leak
Remember: non c'è alcuna garbage collection in C !
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Allocazione e Deallocazione: esempio
int proc() { int k; k=15;
... /* lavora con k */
return 0;};
int proc() { int* k; k = (int*)malloc( sizeof(int) ); *k = 15;
... /* lavora con *k */
free(k); return 0;};
k viene automaticamente allocato (i 4 bytes di memoria necessari al suo immagazzinamento vengono "prenotati").
k viene inizializzato (a 15)
all'uscita dalla procedura, i 4 bytes sono resi di nuovo disponibili
k viene esplicitamente allocato. (a tempo di esecuzione, si trovano i 4 bytes di memoria necessari al suo immagazzinamento. La locazione viene memorizzata in k).
k viene inizializzato (a 15)
all'uscita dalla procedura, dobbiamorendere i 4 bytes di nuovo disponibiliesplicitamente
usando l'allocazione dinamica:
usando l'allocazione automatica delle variabili locali:
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Vi ricordate di quell'altro problemino...
• Cosa succede, se non si sa a priori* quanti elementi di un array ci serviranno**? – * quando scriviamo il programma– ** a tempo di esecuzione
• Necessità allocazione dinamica di array.
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Allocazione di vettori
(void*) calloc(unsigned int n, unsigned int size);
calloc = contiguous allocation
Alloca n elementi contigui ciascuno grande size.
In pratica, alloca un area di memoria grande n x size
Per il resto, funziona come mallocint* p;p = (int*) calloc(100000,sizeof(int) );
Alloca un vettore di 100000 interi.
Esempio:
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Allocazione di vettori
• Ricordiamoci sempre:
int* v = (int*) calloc(100000,sizeof(int) );
int v[100000];
A) fixed size vector:
B) vettore allocato dinamicamente:
• In entrambi i casi:• ho un vettore di 100000 interi• posso scrivere ad esempio:
v[2]= v[0] + 3 * v[1] ;
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Allocazione di vettori
• Ricordiamoci sempre:
int* v = (int*) calloc(100000,sizeof(int) );
int v[100000];
A) fixed size vector:
B) vettore allocato dinamicamente:
• Differenza 1: dimensione variabile• se x è una var intera, posso scrivere:
• ma non posso scrivere:
int* v = (int*) calloc(x,sizeof(int) );
int v[x];
qua è richiesta una costante!
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Allocazione di vettori
• Ricordiamoci sempre:
int* v = (int*) calloc(100000,sizeof(int) );
... /* usa v */
free(v);
int v[100000];
A) fixed size vector:
B) vettore allocato dinamicamente:
• Differenza 2: se ho allocato, devo deallocare
int* v = (int*) calloc(100000,sizeof(int) );
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
• Differenza 3: fixed size = più efficiente• il solito prezzo da pagare per l'uso dei puntatori...• ...maggiorato• mettiamo che v valga 0xAA000000 :
se fixed:
se dinamco:
Allocazione di vettori
• Ricordiamoci sempre:
v[2]
int v[100000];
A) fixed size vector:
B) vettore allocato dinamicamente:
int* v = (int*) calloc(100000,sizeof(int) );
compilazione
compilazionev[2]READ TEMP0 0xAA000000ADD TEMP0 8READ TEMP TEMP0
READ TEMP 0xAA000008
0xAA000000 + 2 x sizeof(int)ma precalcolato staticamente
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
• Differenza 4: • vengono allocati in zone diverse della
memoria...• come vedremo nella lezione sulla
gestione della memoria
Allocazione di vettori
• Ricordiamoci sempre:
int v[100000];
A) fixed size vector:
B) vettore allocato dinamicamente:
int* v = (int*) calloc(100000,sizeof(int) );
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Puntatori: operazioni a basso livello
Esercizio:
• Sappiamo che un double occupa 8 bytes.• Dato un double, quale è il valore di questi
8 bytes?• Per esempio, quali 8 bytes compongono il
valore 3.14159256 ?
un numero in virgola mobilea doppia precisione
di solito, ma dipende dall'implementazione
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Puntatori: operazioni a basso livello
spazio riservato per la variabile d (8 bytes)
int main(){
1B903C321B903C33
1B903C341B903C35
1B903C361B903C37
1B903C381B903C39
1B903C3A1B903C3B
1B903C3C
dobule d;
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Puntatori: operazioni a basso livello
1B903C321B903C33
1B903C341B903C35
1B903C361B903C37
1B903C381B903C39
1B903C3A1B903C3B
1B903C3C
spazio riservato per la variabile d (8 bytes)
c o d i f i c a d i 3 . 1 4 1 5 9 2 5 6
int main(){ dobule d; d = 3.14159256; Byte * v ;
un puntatore a Byte che farà da vettore di Bytes
ma il tipo "Byte" non è definito! Definirlo, ad es fuori dalla proc "main" (vedere lez. 2)
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
v = & d;
Puntatori: operazioni a basso livello
1B903C321B903C33
1B903C341B903C35
1B903C361B903C37
1B903C381B903C39
1B903C3A1B903C3B
1B903C3C
spazio riservato per la variabile d (8 bytes)
c o d i f i c a d i 3 . 1 4 1 5 9 2 5 6
int main(){ dobule d; d = 3.14159256; Byte * v ;
v[0]
v[1]
v[2]
v[3]
v[4]
v[5]
v[6]
v[7]
for (i=0; i<8; i++) printf("%d,",v[i]);
v = (Byte*) & d; for (i=0; i< sizeof(double); i++) printf("%d,",v[i]);
int i;
}
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Puntatori: operazioni a basso livello
• A casa, provate questo programma, e scopriamo:– quali sono gli 8 bytes che compongono il double 3.14159256– quali sono gli 8 bytes che compongono il double 6.022 x 1023
• e, adattando il programma agli interi:– quali sono i 4 bytes che compongono l'int +1000000
– quali sono i 4 bytes che compongono l'int +1
– quali sono i 4 bytes che compongono l'int -1
• a seconda di quale architettura viene usata, potremmo trovare risposte diverse!– domanda: sarebbe potuto succedere in Java?
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Puntatori
• Molto potenti...– vettori di dimensione determinata
dinamicamente– passaggio di parametri per riferimento
• in un linguaggio che prevede passaggio solo per copia
– possibilità di scrivere codici più efficienti– controllo diretto delle risorse, a basso livello– strutture dati flessibili
• per esempio:
typedef struct { char nome[20]; char cognome[20]; int eta; Persona* padre, madre;} Persona;
M a r c o T a r i n i - L a b o r a t o r i o d i L i n g u a g g i - 2 0 0 7 / 0 8 - U n i v e r s i t à d e l l ’ I n s u b r i a
Puntatori
• Molto potenti...
"Ad un grande potere corrisponde una grande responsabilità."
– lo zio di Spiderman