Università dell’Insubria Facoltà di Scienze Matematiche, Fisiche e Naturali di Varese Corso di Laurea in Informatica Anno Accademico 2006/07 Laboratorio di Linguaggi lezione V Marco Tarini Assegnare i Puntatori • In memoria, un puntatore è un indirizzo di memoria – (...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! Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria 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 ! • " void* " puntatore generico, puntatore senza tipo, in pratica, un semplice indirizzo di memoria Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Allocazione: esempio int* p; p = malloc( ? 4 ); Errore di tipo! A sx abbiamo un (int*) mentre a dx un (void*) Il tipo è diverso, ma si tratta sempre di un indirizzo di memoria! Soluzione: basta fare un type-cast: int* p; p = (int*) malloc(4); Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria 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 Il valore resituito dalle malloc va controllato ! int* p; p = (int*) malloc(4); if (p == NULL) { /* finita memoria ... */ } Marco Tarini ‧ Laboratorio di Linguaggi ‧ oppure, più coincisamente if (!p) { 2006/07 ‧ Università dell’Insubria Allocazione typedef struct { /*blah blah... un sacco di campi, array...*/ } TipoStrano TipoStrano* p; p = (TipoStrano *) malloc(sizeof(TipoStrano)); 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! Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria 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 ! Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Allocazione e Deallocazione: esempio k viene automaticamente allocato (i 4 bytes di memoria necessari al suo immagazzinamento vengono "prenotati"). int proc() { int k; k=15; k viene inizializzato (a 15) ... /* lavora con k */ return 0; 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, dobbiamo rendere i 4 bytes di nuovo disponibili esplicitamente Marco Tarini ‧ Laboratorio di Linguaggi ‧ usando l'allocazione dinamica: int proc() { int* k; k = (int*)malloc( sizeof(int) ); *k = 15; ... /* lavora con *k */ free(k); return 0; }; 2006/07 ‧ Università dell’Insubria 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. Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria 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 malloc Esempio: int* p; p = (int*) calloc(100000,sizeof(int) ); Alloca un vettore di 100000 interi. Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Allocazione di vettori • Ricordiamoci sempre: B) vettore allocato dinamicamente: int* v = (int*) calloc(100000,sizeof(int) ); A) fixed size vector: int v[100000]; • In entrambi i casi: • ho un vettore di 100000 interi • posso scrivere ad esempio: v[2]= v[0] + 3 * v[1] ; Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Allocazione di vettori • Ricordiamoci sempre: B) vettore allocato dinamicamente: int* v = (int*) calloc(100000,sizeof(int) ); A) fixed size vector: int v[100000]; • Differenza 1: dimensione variabile • se x è una var intera, posso scrivere: int* v = (int*) calloc(x,sizeof(int) ); • ma non posso scrivere: int v[x]; qua è richiesta una costante! Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Allocazione di vettori • Ricordiamoci sempre: B) vettore allocato dinamicamente: int* v = (int*) calloc(100000,sizeof(int) ); A) fixed size vector: int v[100000]; • Differenza 2: se ho allocato, devo deallocare int* v = (int*) calloc(100000,sizeof(int) ); ... /* usa v */ free(v); Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Allocazione di vettori • Ricordiamoci sempre: B) vettore allocato dinamicamente: int* v = (int*) calloc(100000,sizeof(int) ); A) fixed size vector: int v[100000]; • Differenza 3: fixed size = più efficiente • il solito prezzo da pagare per l'uso dei puntatori... 0xAA000000 + 2 x sizeof(int) • ...maggiorato ma precalcolato staticamente • mettiamo che v valga 0xAA000000 : • se fixed size: v[2] • se dinamco: v[2] compilazione READ TEMP compilazione READ TEMP0 ADD TEMP0 READ TEMP Marco Tarini ‧ Laboratorio di Linguaggi ‧ 0xAA000008 0xAA000000 8 TEMP0 2006/07 ‧ Università dell’Insubria Allocazione di vettori • Ricordiamoci sempre: B) vettore allocato dinamicamente: int* v = (int*) calloc(100000,sizeof(int) ); A) fixed size vector: int v[100000]; • Differenza 4: • vengono allocati in zone diverse della memoria... • come vedremo nella lezione sulla gestione della memoria Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Puntatori: operazioni a basso livello Esercizio: un numero in virgola mobile a doppia precisione di solito, ma dipende dall'implementazione • 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 ? Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Puntatori: operazioni a basso livello 1B903C32 1B903C33 1B903C34 1B903C35 1B903C36 1B903C37 1B903C38 1B903C39 1B903C3A 1B903C3B 1B903C3C spazio riservato per la variabile d (8 bytes) int main() { dobule d; Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Puntatori: operazioni a basso livello 1B903C32 1B903C33 1B903C34 1B903C35 1B903C36 1B903C37 1B903C38 1B903C39 1B903C3A 1B903C3B 1B903C3C codifica di 3.14159256 spazio riservato per la variabile d (8 bytes) 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) int main() { dobule d; d = 3.14159256; Byte * v ; Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Puntatori: operazioni a basso livello 1B903C32 1B903C33 1B903C34 1B903C35 1B903C36 1B903C37 1B903C38 1B903C39 1B903C3A 1B903C3B 1B903C3C vc[0]o dv[1] v[6]2 5v6 [7] i f i vc[2]a dv[3] i 3v.[4]1 4v[5] 159 spazio riservato per la variabile d (8 bytes) int main() { dobule d; int i; d = 3.14159256; Byte * v ; v = & (Byte*) d; & d; for (i=0; i< i<8; sizeof(double); i++) i++) printf("%d,",v[i]); }; Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria 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? Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Ricapitoliamo: uso dei 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; Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria Puntatori • Molto potenti... "Ad un grande potere corrisponde una grande responsabilità." – lo zio di Spiderman Marco Tarini ‧ Laboratorio di Linguaggi ‧ 2006/07 ‧ Università dell’Insubria