La memoria per array statici e dinamici

  1. quando si usano, array statici e dinamici sembrano uguali (gli elementi sono sempre a[i] ecc.
  2. in memoria, non sono la stessa cosa
  3. & e sizeof di un array statico e di un dinamico
  4. confronto con &(a[0]) nei due casi
  5. per i vettori dinamici, si può cambiare la zona di memoria occupata

Se si fa int a[10] oppure int *b e poi b=malloc(10*sizeof(int)), si ottiene in entrambi i casi un vettore di 10 elementi. Da questo punto in poi, sono definite le variabili a[0], a[1] ecc, cosí come le variabili b[0], b[1], ecc.

Esistono però delle differenze nel modo in cui questi due vettori sono memorizzati. Questo risulta evidente se si prova a stampare indirizzo e numero di byte occupati da essi, come viene fatto nel programma statdin.c riportato qui sotto.

/*
  Differenza di allocazione di memoria fra
array statici e dinamici.
*/

#include<stdlib.h>

int main() {
  int a[10];
  int *b;

  b=malloc(10*sizeof(int));

		/* da questo punto in poi, a e b sembrano uguali, ma... */

  printf("a: indirizzo=%x indirizzo primo elemento=%x byte occupati=%d\n",
         &a, &(a[0]), sizeof(a));

  printf("b: indirizzo=%x indirizzo primo elemento=%x byte occupati=%d\n",
         &b, &(b[0]), sizeof(b));

  return 0;
}

Quello che si ottiene è un output di questo genere:

a: indirizzo=bffff428 indirizzo primo elemento=bffff428 byte occupati=40
b: indirizzo=bffff424 indirizzo primo elemento=8049688 byte occupati=4

Le differenze sono evidenti. Per prima cosa, l'indirizzo del vettore b non coincide con l'indirizzo del suo primo elemento b[0]. Secondo, il numero di byte occupati non è più pari al numero di byte occupati da ogni elemento moltiplicato per il numero di elementi. Si può anzi facilmente verificare che il numero di byte occupati da b non cambia se si allocano più o meno elementi.

La prima figura mostra il modo in cui è disposto in memoria un array statico. Sono evidenziati gli indirizzi del vettore stesso, e dei suoi primi elementi.

Il caso del vettore dinamico è differente. Un vettore dinamico è in effetti un puntatore a intero, dal momento che è stato definito come int *b. Questo significa che occupa lo spazio che occupano tutti gli altri puntatori (per esempio, quattro elementi). Nel nostro caso, b occupa quattro elementi, come nella figura.

Quando si esegue la istruzione malloc(10*sizeof(int)), viene riservata una zona di memoria grande abbastanza da contenere 10 interi. Si noti che la variabile puntatore b non è un argomento di malloc. Questo significa che la funzione malloc non influenza la variabile b, tranne che per il fatto che in essa viene messo l'indirizzo di inizio della zona di memoria creata da malloc

Questo spiega perfettamente la figura a fianco: la variabile b è un puntatore, e quindi ha la dimensione che hanno tutti i puntatori. Quando si crea la zona di memoria, l'indirizzo iniziale viene messo in questa variabile puntatore.

Perchè si può accedere alla zona di memoria creata da malloc usando b[0], b[1], ecc.? Questa è una nuova regola sui puntatori.

Quello che si è detto nella parte sui puntatori è che, se b è un puntatore a intero, allora *b si comporta come una variabile di tipo intero. Un altro modo di accedere alla zona di memoria è questo: se b è un puntatore a intero, allora b[0] è equivalente a *b. Questo significa che b[0] è la variabile la cui zona di memoria associata è costituita dai byte a partire dall'indirizzo contenuto in b.

Per b[1] vale una regola analoga: dal punto di vista della programmazione ad alto livello, è equivalente a una variabile; la sua zona di memoria associata è quella subito sopra a b[0]. Lo stesso vale per b[2] ecc. Volendo riassumere, se b è una variabile di tipo puntatore a intero, allora si comporta come un vettore di interi, la cui dimensione dipende dal numero di byte creati con malloc. In questo gli array statici e dinamici si comportano nello stesso modo. La differenza si vede quando si determinano l'indirizzo del primo elemento del vettore e la dimensione totale del vettore.

Un'altra differenza fra array statici e dinamici è che la zona di memoria associata a un vettore statico rimane sempre la stessa durante la esecuzione del programma. Al contrario, per i vettori dinamici può cambiare. Per esempio, è possibile fare:

  int *b;

  b=malloc(10*sizeof(int));

  /* alcune operazioni */

  b=malloc(20*sizeof(int));

Alla fine della seconda malloc la dimensione del vettore è cambiata, e anche l'inizio della zona di memoria occupata può non essere lo stesso. Quindi, mentre &(a[0]) rimane sempre lo stesso durante l'esecuzione di un programma, se a è un array statico, lo stesso non vale se si tratta di un array dinamico.