Zone di memoria inaccessibili

  1. il valore iniziale della memoria è indeterminato
  2. se non si perde l'indirizzo di una zona di memoria allocata con malloc, non la si può più usare

Si consideri il seguente programma inacc.c. Cosa viene stampato?

#include<stdlib.h>

int main() {
  int *p;

  p=malloc(sizeof(int));
  *p=12;

  p=malloc(sizeof(int));

  printf("%d\n", *p);

  return 0;
}

Per trovare la soluzione a problemi di questo genere, occorre disegnare l'evoluzione dello stato della memoria quando si esegue il programma. Si usano ovviamente dei valori di esempio per le posizioni di memoria, dal momento che i valori esatti vengono determinati solo quando si esegue il programma.

La fingura qui accanto mostra lo stato della memoria dopo la creazione della variabile: l'unica zona di memoria attualmente riservata è quella che corrisponde a p. Il valore in essa contenuta è tuttora indefinito.

Dopo aver effettuato l'operazione di allocazione, viene creata una zona di memoria, e il suo indirizzo viene memorizzato in p. Lo stato della memoria è quindi come quello qui a sinistra. L'istruzione *p=12 mette il valore 12 nella zona di memoria che era stata allocata. Lo stato della memoria dopo questa operazione è riportato qui a destra.

A questo punto viene fatta la seconda malloc. La regola della allocazione di memoria dice che la zona di memoria che viene restituita è una zona che il programma può usare, e che non è già usata. Quindi, la zona di memoria riservata da malloc non può essere nè la zona di memoria di una variabile nè una zona che è stata già allocata in precedenza.

La situazione che si viene a creare è quindi che abbiamo una seconda zona di memoria riservata, il cui indirizzo iniziale viene scritto in p. In altre parole, p contiene l'indirizzo della zona di memoria che è stata allocata con la seconda chiamata alla funzione malloc.

Cosa viene stampato? L'istruzione printf("%d\n", *p) stampa il contenuto della zona di memoria che è stata allocata dalla seconda chiamata alla funzione malloc. D'altra parte, nessun valore è stato memorizzato in questa zona. Il valore che viene stampato dipende quindi dai valori iniziali della memoria, ossia è indefinito.

Quello che vale per le variabili, ossia che il loro valore è indefinito finchè un valore non viene memorizzato in esso, continua a valere.

Un'altra osservazione importante che si puè fare su questo programma è che non è più possibile accedere alla prima zona di memoria, quella creata dalla prima chiamata di malloc. Infatti, l'unico modo per accedere a una zona di memoria è quello di conoscere il suo indirizzo, ma l'indirizzo di questa zona era stato memorizzato in p e poi sovrascritto. Il programma non può quindi sapere quale è l'indirizzo di questa zona, e non può quindi accedere ad essa.

Si noti che è possibile accedere a una zona di memoria scrivendo nel programma p=0xeff11: l'indirizzo eff11 è infatti soltanto un valore di esempio: il valore di ritorno effettivo della prima chiamata a malloc viene determinato soltanto in esecuzione, e più esecuzioni dello stesso programma in genere producono risultati diversi.

Tutto questo dice che, se il valore di ritorno della chiamata a malloc viene perso, non c'è più modo per accedere alla zona di memoria che era stata riservata.

Nella rappresentazione con freccie, l'evoluzione della memoria è la seguente.

 
Creazione della variabile p Dopo la prima malloc
Dopo l'istruzione *p=12 Dopo la seconda malloc