sabato, novembre 04, 2006

Allocazione dinamica della memoria


#include <stdio.h>
#include <stdlib.h>
#include <new.h>
int main() {

/*
L'importanza del fatto che ogni puntatore "sappia" a quale tipo di variabile
stia puntando (ovvero di quale tipo di variabili puo' contenere l'indirizzo)
risiede nella possibilita' di eseguire operazioni algebriche con il contenuto
di variabili puntatori, ossia di eseguire operazioni algebriche fra indirizzi.

Tali operazioni algebriche hanno senso nel contesto degli array, dal momento
che gli array non sono altro che porzioni contigue di memoria gestite proprio
(eventualmente implicitamente) tramite puntatori.

Per capire meglio l'assoluta sovrapposizione fra array e puntatori, conviene
partire dall'uso dei puntatori per una gestione dinamica della memoria.
*/


/*
Invece che assegnare ad un puntatore l'indirizzo di una variabile gia' dichiarata
e' possibie assegnargli l'indirizzo di una NUOVA zona di memoria che chiediamo
ci venga messa a disposizione (meglio: il codice che state scrivendo chiedera'
al sistema operativo di mettergli a disposizione).
Per chiedere (o rilasciare) memoria, il C++ mette a disposizione i comandi
new
delete
*/

//
//NEW e DELETE
//

int *p; //dichiaro un puntatore a interi
p = new int; //sintassi di new:
/*
alloco in memoria un intero (dopo la keyword "new" si specifica il tipo di
variabile da allocare), e ne restituisco il suo indirizzo.
Siccome a sinitra c'e' un puntatore a interi, l'espressione e' corretta,
e pi conterra' dunque l'indirizzo di una NUOVA porzione di memoria adatta
a contenere numeri interi
*/

delete p; //sintassi di delete:
/*
Attenzione: delete non elimina la variabile p (che e' un puntatore), ma
semplicemente de-alloca la memoria che era stata allocata prima con new
e il cui indirizzo era stato memorizato proprio nella variabile puntatore pi.
Nota Bene:
delete riconosce l'indirizzo di memoria, non la variabile puntatore usata
al momento dell'allocazione, con new.
Ovvero, e' possibile fare la cosa seguente:
*/

int *p1, *p2; //alloco due puntatori;
p1 = new int; //creo un intero dinamicamente, e il suo indirizzo lo assegno a p1
p2 = p1; //metto in p2 l'indirizzo che avevo memorizzato in p1;
delete p2; //disalloco la variabile intera dinamicamente creata, anche se
//l'avevo creata usando p1...
//Ovvero: ora p1 punta ad una zona di memoria che non abbiamo piu' il diritto
//di usare (il sistema operativo potrebbe usarla per altro, e quindi il suo
//contenuto essere del tutto impredicibile...)



//
//NEW e DELETE e gli array
//

//Ma l'uso piu' comune di new e delete e' con gli array dinamici:

int *P1;
P1 =
new int[10]; //alloco non uno solo, ma 10 interi
//Le variabili cosi' create sono contigue l'una all'altra, in memoria.
//In particolare e' l'indirizzo della prima di esse che viene restituito da new.
//Quindi P1 ora contine l'indirizzo della prima locazione di memoria di
//una serie contigua di 10 locazioni per numeri interi.

/*
Una delle cose importanti da notare e' che la quantita' di memoria che e'
possibile allocare con new non deve necessariamente essere predeterminata
compilation-time (come avveniva con gli array) ma puo' essere determinata
run-time per mezzo del valore corrente di una qualche variabile
*/
int quanti_double;
printf(
"Quanti double vuoi allocare?\n");
scanf(
"%d",&quanti_double);
double *Pd;
Pd =
new double[quanti_double];


//E se inserite un numero troppo elevato?
//Il programma si interrompe con un errore!!!

//E se volete gestire un errore del genere dall'interno del vostro programma?

printf("Prova ad allocare tantissimi double! Quanti?\n");
scanf(
"%d",&quanti_double);
Pd =
new (nothrow) double[quanti_double];
if (Pd == 0) {
printf(
"Bravo! Hai davvero esagerato!\n%d double sono davvero troppi per la mia memoria!!!\n\n",quanti_double);
}
else {
printf(
"Niente da fare:\nho abbastanza memoria da allocare tutti e %d i double richiesti!\n\n",quanti_double);
}

//La versione di new con l'opzione (nothrow) restituisce un puntatore nullo (0)
//nel caso in cui la richiesta di allocazione non puo' essere soddisfatta,
//e continua l'esecuzione del programma (ma, ovviamente, senza la memoria
//allocata!!!)


/*
Il comando delete usato per gli array dinamici gestisce automaticamente
la dimensione dell'array, e non e' necessario che la specifichi il
programmatore:
*/

delete[] Pd;
//Notare, pero', che siccome Pd punta al primo indirizzo di un array
//(e non ad una variabile singola), la sintassi preve l'uso delle
//parentesi quadre (vuote)
//Se per caso Pd e' il puntatore nullo (nel caso in cui abbiate
//esagerato con la richiesta di double...), il comando delete non produce
//alcun risultato (non c'e' nulla da de-allocare...)


return 0;

}


Nessun commento: