Puntatori e gestione dinamica della memoria Corso di

  • Slides: 47
Download presentation
Puntatori e gestione dinamica della memoria Corso di Informatica 2 a. a. 2003/04 Lezione

Puntatori e gestione dinamica della memoria Corso di Informatica 2 a. a. 2003/04 Lezione 4 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Vantaggi nell’uso dei vettori • Sono legati all’accesso diretto agli elementi utilizzando gli indici.

Vantaggi nell’uso dei vettori • Sono legati all’accesso diretto agli elementi utilizzando gli indici. d = dimensione elemento v indirizzo v[i] = b + i d v[i] b = indirizzo base i = indice (spiazzamento) Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Indirizzamento della RAM 000 0 001 1 010 011 23 100 101 110 111

Indirizzamento della RAM 000 0 001 1 010 011 23 100 101 110 111 0 0 1 1 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Problemi nell’uso dei vettori • La dimensione di un vettore deve essere fissata al

Problemi nell’uso dei vettori • La dimensione di un vettore deve essere fissata al momento della compilazione: int v[100]; // non int v[dim]; con dim variabile • L’inserimento di un nuovo valore comporta lo slittamento di tutti quelli alla sua destra: for (j = indice_prox_loc_libera; v[j] = v[j-1]; v[i] = nuovo_valore; j > i; j--) Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

I puntatori • Un puntatore è una variabile il cui dominio di definizione sono

I puntatori • Un puntatore è una variabile il cui dominio di definizione sono gli indirizzi di memoria <tipo>* <variabile>; int* p; // puntatore a intero int *p, *q; // breve per int* p; int* q; Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Dereferenziazione (*) • L’operatore di dereferenziazione (* <puntatore>) legge/scrive alla locazione di memoria il

Dereferenziazione (*) • L’operatore di dereferenziazione (* <puntatore>) legge/scrive alla locazione di memoria il cui indirizzo è il valore del suo operando p 025 fe 16 2983 *p == 2983 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Operatore indirizzo (&) • Se x è una variabile, &x è l’indirizzo a cui

Operatore indirizzo (&) • Se x è una variabile, &x è l’indirizzo a cui sono memorizzati i suoi valori 025 fe 16 x 2983 &x == 025 fe 16 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Esempio // esempio di dereferenziazione e // uso dell’oporatore & #include <iostream. h> int

Esempio // esempio di dereferenziazione e // uso dell’oporatore & #include <iostream. h> int main() { int x = 7; int *p 1, *p 2; // oppure int* p; int* q; p 1 = &x; p 2 = p 1; cout << “*p 2 = “ << *p 2 << endl; // stampa il valore di x cioe’ 7 cout << “p 2 = “ << p 2 << endl; // stampa il valore di p 2 cioe’ // l’indirizzo di x } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Condivisione (sharing) I puntatori possono condividere l’area di memoria cui puntano: int *p, *q;

Condivisione (sharing) I puntatori possono condividere l’area di memoria cui puntano: int *p, *q; int n = 44; p = q = &n; p q n 44 Ogni modifica del valore di n che avvenga per assegnazione su *p si riflette su n e su *q. Questa caratteristica viene sfruttata per ottonere effetti collaterali sui valori dei parametri attauli, passandoli cioè per indirizzo. Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Riferimenti In C++ si può avere sharing anche senza i puntatori, usando riferimenti, ovvero

Riferimenti In C++ si può avere sharing anche senza i puntatori, usando riferimenti, ovvero sinonimi (alias): <tipo>& <nome rif> = <nome var> int main () { int n = 44; int& rn = n; // rn è sinonimo di n n--; cout << rn << endl; // stampa 43 } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Vettori e puntatori in C++ • In C++ un vettore è una costante di

Vettori e puntatori in C++ • In C++ un vettore è una costante di tipo puntatore: int v[100]; int* p; p = v; // il valore di p è l’ind. di base di v // ossia p == &v[0] • Si può usare la notazione con gli indici per i puntatori che si riferiscono a vettori: p[i] … // equivale a v[i] Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Aritmetica dei puntatori (1) • Ad ogni tipo di dato corrisponde la dimensione in

Aritmetica dei puntatori (1) • Ad ogni tipo di dato corrisponde la dimensione in byte della memoria necessaria per contenere i suoi valori: int sizeof(<tipo>) // C: ritorna la dim. • I puntatori sono tipati: ciò è essenziale per sapere cosa leggere/scrivere alle locazioni di memoria cui puntano Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Aritmetica dei puntatori (2) • In C++ si possono sommare (o sottrarre) interi a

Aritmetica dei puntatori (2) • In C++ si possono sommare (o sottrarre) interi a puntatori: int *p, *q; q = p + 10; // il valore di q == // valore di p + 10*sizeof(int) Quindi, se p punta ad un vettore v: p+i == &v[i] // ovvero *(p+i) == v[i] == p[i] Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Aritmetica dei puntatori (3) • incremento e decremento: int *p; p = &n; p++;

Aritmetica dei puntatori (3) • incremento e decremento: int *p; p = &n; p++; /* p punta a &n + sizeof(int) */ • somma e sottrazione di un intero: int n, m, *p; p = &n; p = p + m; /* p punta a &n + m * sizeof(int) */ • differenze tra puntatori: int n, a, b, *p, *q; p = &a, q = &b; n = p - q; /* n è il numero degli interi allocabili tra gli indirizzi di a e di b */ • confronto tra puntatori: int n, m, *p; p = &n; q = &m; if (p < q) … /* eseguito se l’indirizzo di n è minore di quello di m */ Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Esempio void Inverti (int v[]; int lun); // inverte l’ordine degli el. di v[lun]

Esempio void Inverti (int v[]; int lun); // inverte l’ordine degli el. di v[lun] { int t, *p, *q; for(p = v, q = p + (lun-1); p < q; p++, q--) { t = *p; *p = *q; *q = t; } } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di parametri per valore void f(int n){ n++; } int a = 0;

Passaggio di parametri per valore void f(int n){ n++; } int a = 0; f(a); cout << a; a 0 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di parametri per valore void f(int n){ n++; } int a = 0;

Passaggio di parametri per valore void f(int n){ n++; } int a = 0; f(a); cout << a; a 0 n 0 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di parametri per valore void f(int n){ n++; } int a = 0;

Passaggio di parametri per valore void f(int n){ n++; } int a = 0; f(a); cout << a; a 0 n 1 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di parametri per valore void f(int n){ n++; } int a = 0;

Passaggio di parametri per valore void f(int n){ n++; } int a = 0; f(a); cout << a; a 0 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di par. per riferimento void f(int& n) { n++; } int a =

Passaggio di par. per riferimento void f(int& n) { n++; } int a = 0; f(a) cout << a; a 0 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di par. per riferimento void f(int& n) { n++; } int a =

Passaggio di par. per riferimento void f(int& n) { n++; } int a = 0; f(a) cout << a; a 0 n Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di par. per riferimento void f(int& n) { n++; } int a =

Passaggio di par. per riferimento void f(int& n) { n++; } int a = 0; f(a) cout << a; a 1 n Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di par. per riferimento void f(int& n) { n++; } int a =

Passaggio di par. per riferimento void f(int& n) { n++; } int a = 0; f(a) cout << a; a 1 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di par. per puntatore void f(int* pn) { *(pn++); } int a =

Passaggio di par. per puntatore void f(int* pn) { *(pn++); } int a = 0; f(&a) cout << a; a 0 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di par. per puntatore void f(int* pn) { *(pn++); } int a =

Passaggio di par. per puntatore void f(int* pn) { *(pn++); } int a = 0; f(&a) cout << a; 0 a pn Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di par. per puntatore void f(int* pn) { *(pn++); } int a =

Passaggio di par. per puntatore void f(int* pn) { *(pn++); } int a = 0; f(&a) cout << a; 1 a pn Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Passaggio di par. per puntatore void f(int* pn) { *(pn++); } int a =

Passaggio di par. per puntatore void f(int* pn) { *(pn++); } int a = 0; f(&a) cout << a; a 1 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Allocazione dinamica • Allocazione = destinazione di una certa quantità di memoria per contenere

Allocazione dinamica • Allocazione = destinazione di una certa quantità di memoria per contenere valori di un dato tipo • Tutte le variabili di un programma sono allocate quando sono in uso (puntatori inclusi) • E’ possibile allocare memoria durante l’esecuzione del programma in una area specifica detta “memoria dinamica” Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Allocazione dinamica: new int *p; p = new int; *p = 2983; p 025

Allocazione dinamica: new int *p; p = new int; *p = 2983; p 025 fe 16 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Allocazione dinamica: new int *p; p = new int; *p = 2983; p 025

Allocazione dinamica: new int *p; p = new int; *p = 2983; p 025 fe 16 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Allocazione dinamica: new int *p; p = new int; *p = 2983; p 025

Allocazione dinamica: new int *p; p = new int; *p = 2983; p 025 fe 16 2983 Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Allocazione dinamica: new float* p; *p = 3. 14159; // ERRORE: p non è

Allocazione dinamica: new float* p; *p = 3. 14159; // ERRORE: p non è allocato float x = 3. 14159; float *p = &x // OK: p usa l’allocazione di x float* p = new float; *p = 3. 14159; // OK: p è allocato Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Allocazione dinamica in C Tipo *p; p = (Tipo*) malloc (sizeof(Tipo)); Alloca una struttura

Allocazione dinamica in C Tipo *p; p = (Tipo*) malloc (sizeof(Tipo)); Alloca una struttura dati la cui dimensione in byte dipende da Tipo ed è calcolata da sizeof; in caso di successo assegna il tipo Tipo* all’indirizzo di inizio del blocco, ed il valore è salvato in p. Se non c’è più memoria disponibile, malloc ritorna NULL, che sarà allora il valore di p. Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Allocazione dinamica di un vettore Per allocare dinamicamente un vettore occorre conoscere: 1. Il

Allocazione dinamica di un vettore Per allocare dinamicamente un vettore occorre conoscere: 1. Il tipo dei suoi elementi; 2. il numero di questi elementi (che tuttavia potrà essere noto anche solo al momento dell’esecuzione). int *v, lun; v = new int[lun]; // in C++ v = (int*) malloc (sizeof(int)*lun); // in C Alloca un vettore di lun interi, dove però lun è una variabile. Comunque, una volta allocato, v punterà ad un vettore la cui lunghezza non è più modificabile. Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Le stringhe • Le stringhe sono vettori di caratteri, contenenti un terminatore: ‘�’ char

Le stringhe • Le stringhe sono vettori di caratteri, contenenti un terminatore: ‘’ char s[] = “Salve mondo”; char s[MAXLUN]; char *s = “Salve mondo”; • Esiste un tipo stringa, definito: typedef char* String; Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Allocazione di stringhe • E’ opportuno costruire una funzione di allocazione (allocatore o generatore)

Allocazione di stringhe • E’ opportuno costruire una funzione di allocazione (allocatore o generatore) per ogni struttura dati che si implementa: String Str. Alloc(int len) { String *s; s = new String[len + 1]; // len + 1 per far posto a ‘’ return s; } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Operazioni sulle stringhe (1) int strlen (String s) { int n = 0; while

Operazioni sulle stringhe (1) int strlen (String s) { int n = 0; while (*s++ != ‘’) n++; return n; } int strcpy (String dest; String source) { while((*dest++ = *source++)!= ‘’); } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Operazione sulle stringhe (2) String Leggi. Stringa (void) { char buffer[MAXLUN]; String s; gets(buffer);

Operazione sulle stringhe (2) String Leggi. Stringa (void) { char buffer[MAXLUN]; String s; gets(buffer); s = Stralloc(strlen(buffer)); strcpy(s, buffer); return s; } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

I record Un record è una tupla di valori di tipi possibilmente diversi acceduti

I record Un record è una tupla di valori di tipi possibilmente diversi acceduti attraverso etichette: struct <nome struttura> { <tipo 1> <etichetta campo 1>; . . . <tipok> <etichetta campok>; } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Allocazione dinamica di record (strutture) • Come per i tipi di base e per

Allocazione dinamica di record (strutture) • Come per i tipi di base e per i vettori, si possono allocare record: typedef struct Record {int field; …} *My. Record; My. Record = new Record; • Data la frequenza dell’uso di puntatori a record, il C++ usa la sintassi: p->field invece di (*p). field Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Un modo per definire il tipo vettore (1) • Un buon metodo per definire

Un modo per definire il tipo vettore (1) • Un buon metodo per definire un vettore da allocare dinamicamente è usare un record con un campo lunghezza: typedef Vec. Rec* Vettore; typedef struct vecrec { int lun; int* vec; } Vec. Rec; Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Un modo per definire il tipo vettore (2) v n n – elementi del

Un modo per definire il tipo vettore (2) v n n – elementi del vettore Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Un modo per definire il tipo vettore (3) Vettore Vett. Alloc (int lunghezza) {

Un modo per definire il tipo vettore (3) Vettore Vett. Alloc (int lunghezza) { Vettore v; v = new Vec. Rec; v->lun = lunghezza; v->vec = int[lunghezza]; return v; } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Un esempio più complesso: matrici (1) typedef Matr. Rec* Matrice; typedef struct matrmec {

Un esempio più complesso: matrici (1) typedef Matr. Rec* Matrice; typedef struct matrmec { int righe, colonne; int **vecrighe; } Matr. Rec; n m m n Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Un esempio più complesso: matrici (2) Matrice Nuova. Matrice (int r, int c) {

Un esempio più complesso: matrici (2) Matrice Nuova. Matrice (int r, int c) { Matrice m; int i; m = new Matr. Rec; m->righe = r; m->colonne = c; m->vecrighe = new int*[r]; for (i = 0; i < r; i++) m->vecrighe[i] = new int[c]; return m; } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Deallocazione • La memoria dinamica allocata può essere recuperata usando la funzione delete: delete

Deallocazione • La memoria dinamica allocata può essere recuperata usando la funzione delete: delete <puntatore> • Per deallocare un vettore non occorre ricordarne la dimensione: delete [] <nome vettore> • Per deallocare una struttura complessa come matrice occorrono tante chiamate di delete quante sono state quelle di new Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4

Deallocazione di Matrice void Dealloca. Matrice (Matrice m) { int i; for(i = 0;

Deallocazione di Matrice void Dealloca. Matrice (Matrice m) { int i; for(i = 0; i < m->righe; i++) delete [] m->vecrighe[i]; delete [] m->vecrighe; delete m; } Ugo de'Liguoro - Informatica 2 a. a. 03/04 Lez. 4