Linguaggio C - Puntatori

Problemi derivanti dall'uso di puntatori

Durante l'impiego dei puntatori, si possono generare 2 situazioni anomale, che di norma risultano anche di difficile individuazione durante il debug:
  1. Dangling references.
    Questa situazione ricorre durante l'accesso tramite puntatore ad un'area di memoria non (piu') allocata.
    Esempio:
      int *p;                       /* puntatore a intero (definizione) */
      ...
      p=(int *)malloc(sizeof(int)); /* allocazione della memoria */
      ...
      *p=57;                        /* impiego dell'area allocata */
      ...
      free(p);                      /* deallocazione memoria */
      *p=20;                        /* ERRORE - DANGLING REFERENCE */
                                    /* L'area di memoria puntata da p non e'
                                     * piu' disponibile !!!! */
      ...                                  
      p=NULL;                       /* CORRETTO */
                                    /* Non accedo alla memoria puntata da p, ma
                                     * accedo a p e lo faccio puntare a NULL */
              
  2. Aree non piu' utilizzabili.
    Questo problema avviene quando, per un qualsiasi motivo, viene perso l'indirizzo di un'area di memoria ancora allocata.
    Chiaramente l'area di memoria interessata non e' piu' referenziabile e nemmeno deallocabile !!!.
    Esempio:
      int *p1, *p2;                   /* definizione di 2 puntatori a intero */
      ...
      p1=(int *)malloc(sizeof(int));  /* alloco 1^ area di memoria */
      p2=(int *)malloc(sizeof(int));  /* alloco 2^ area di memoria */
      *p1=75;                         /* utilizzo 1^ area di memoria */
      *p2=*p1;                        /* utilizzo 2^ area di memoria */
                                      /* ora le aree di memoria puntate da p1 e da
                                       * p2, contengono gli stessi valori */
      p2=p1;                          /* ERRORE - p2 punta alla stessa area di 
                                       * memoria puntata da p1.
                                       * Non posso piu' accedere all'area di memoria
                                       * allocata con la seconda malloc() !!! */
              


Indirizzo di una variabile - operatore indirizzo &

Ad un puntatore puo' essere assegnato direttamente l'indirizzo dell'area di memoria riferita ad una variabile, per mezzo dell'operatore indirizzo &.
Esempio:
  int a=5;
  int *p;
  p=&a;                         /* p punta alla locazione di a */
  *p=6;                         /* a vale 6 */
    


Puntatori vs. array - aritmetica degli indirizzi

Nel C, il nome di un array viene impiegato (dal compilatore) come puntatore al suo 1° elemento. Da questa considerazione, ne deriva che gli array possono essere indirizzati indifferentemente o facendo ricorso all'indice, oppure tramite l'aritmetica degli indirizzi.
Esempio:
  float a[15];  /* array di 15 elementi con indice da 0 a 14 */
  int i;

  i=5;
  a[i]=10.0;    /* accesso tramite indice */
  *(a+i)=10.0;  /* aritmetica degli indirizzi: equivale alla forma
                 * precedente */
    
In modo del tutto analogo un puntatore puo' essere trattato come un array:
  int i;
  float a[15];
  float *p;

  p=a;          /* equivale a p=&a[0] */
                /* assegno a p l'indirizzo del primo elemento di a */
  i=5;
  *(p+i)=10.0;  /* aritmetica degli indirizzi: tratto p come puntatore */
  p[i]=10.0;    /* tratto p come se fosse un array */
    
Da notare che per assegnare l'indirizzo del primo elemento di un array a, a rigor di logica occorre riferirsi al primo elemento dell'array ed applicare l'operatore indirizzo &, cioe: p=&a[0]
In realta' il compilatore, interpreta il nome della variabile array come un puntatore inizializzato al primo elemento dell'array, quindi e' sufficiente scrivere p=a per assegnare l'indirizzo dell'array al puntatore p
Sebbene il compilatore consideri del tutto equivalenti le due forme a[i] e *(a+i), tuttavia esiste una differenza importantissima fra il nome di un array ed un puntatore:
il puntatore e' una variabile a tutti gli effetti, quindi puo' venirgli assegnato un indirizzo, puo' essere incrementato, decrementato, ...
il nome di un array e' invece un valore costante dell'indirizzo, pertanto non puo' essere soggetto ad assegnamenti e/o variazioni.

L'aritmetica degli indirizzi consente di sommare (sottrarre) ad un puntatore un valore intero. Dal punto di vista logico, equivale a dire che si vuole accedere a tanti elementi successivi (precedenti) a quello referenziato dal puntatore. In realta' l'indirizzo del puntatore viene incrementato (decrementato) della quantita' indicata ma moltiplicata per la dimensione dell'elemento. Esempio:

  double *pdouble;
  ...
  pdouble=(double *)malloc(10*sizeof(double); /* alloco memoria per 10 double */
  *(pdouble+3)=50.7;
    
Nel caso presentato e' evidente che voglio accedere al 3° elemento successivo a quello puntato da pdouble. E' anche evidente che la distanza di memoria tra questi 2 elementi e' pari a 3*sizeof(double) byte. E' compito del compilatore indirizzare correttamente la memoria fisica, tenendo conto di queste considerazioni.


Indice-C Indice linguaggio C
At Home Umberto Zappi Home Page