ARRAY COME PUNTATORI

Nel linguaggio C gli array sono realizzati come una successione di variabili distinte allocate una dopo l'altra e l'array è essenzialmente un puntatore, precisamente il puntatore alla (indirizzo della) variabile che corrisponde al primo elemento dell'array.
Pertanto in C esiste una dualità tra array e puntatori di cui è bene essere consci.

Consideriamo questa dualità su un esempio

int X[10];
int *PX;
la situazione della memoria dopo queste dichiarazioni è come segue:

xxx

dove le celle di memoria (variabili/scatole) X[0], ..., X[9] hanno indirizzi consecutivi, ed X è inteso come un modo per riferirsi a X[0].
PX è una variabile che può contenere un indirizzo di variabile intera.

Si ha che valgono le seguenti identità

x == &x[0]
&x[1] == (&x[0])+1
&x[2] == (&x[1])+1
...
&x[9] == (&x[8])+1
Assumiamo di eseguire PX = &X[0];
La nuova situazione è:

xxx

e si ha che valgono

*(PX+1) == X[1]
...
*(PX+9) == X[9]
Ma poichè X non è una variabile, abbiamo che X = ...; è errato;
mentre PX è una variabile, e quindi PX = ...; è corretto.

ESEMPIO

#include <stdio.h>

main(){
    int x[10] = {0,1,2,3,4,5,6,7,8,9};
    int * px = NULL, z;
    
    px = &x[0];
    px = px+1;
    
    if(x[1] == *px) printf("va bene \n");
    else printf("va male\n");
    
    if(x == &x[0]) printf("torna tutto \n");
    else printf("qualcosa non va\n");
    
    px = px +2;
    printf("il valore del contenuto di px e\' %d\n",*px);
    
    px = &x[0];
    /*x = x+1; errore*/
    z = px[3];
    printf("il valore di px[3] e\' %d\n",z);
    /*z = (*px)[3]; errore*/
    z = *(px+3);
    printf("il valore di *(px+3) e\' %d\n",z);
}
produrrà come output
va bene 
torna tutto 
il valore del contenuto di px e' 3
il valore di px[3] e' 3
il valore di *(px+3) e' 3

Una conseguenza di questa peculiarità del C riguarda i parametri delle funzioni di tipo array: come al solito sono parametri valori, ma i parametri di tipo array sono dei puntatori al primo elemento, quindi effettivamente essi sono dei parametri variabili.

Pertanto se volete un parametro valore di tipo array dovete controllare voi di non modificarlo all'interno della funzione; se invece volete un parametro variabile di tipo array, non dovete fare nulla (diversamente dal caso di un parametro variabile di altri tipi, vedere qui).
Si consiglia di indicare con dei commenti quando un parametro di tipo array è un valore e quando è una variabile.

ESEMPIO

#include <stdio.h>
#define DIM 5

int VSum(int v[] /*valore*/, int dim)
{
   int sum = 0, i;
   
   for(i=0; i < dim; i++)
      sum += v[i];
   return sum;
}

int VSumP(int * pv, int dim)
{
   int sum = 0, i;
   
   for(i=0; i < dim; i++)
      sum += *(pv+i);
   return sum;
}

void VPrint(int v[ ] /*valore*/, int dim)
{
   int i;
   
   for(i=0; i < dim; i++)
      printf("%5d ",v[i]);
    printf("\n");
}

void VPrintP(int * pv, int dim)
{
   int i;
   
   for(i=0; i < dim; i++){
      printf("%5d ",*pv);
      pv = pv+1;
   };
   printf("\n");
}

void VRead(int v[ ] /*variabile*/, int dim)
{
   int i;
   
   for(i=0; i < dim; i++)
      scanf("%d",&v[i]);
}

void VReadP(int * pv, int dim)
{
   int i;
   
   for(i=0; i < dim; i++)
      scanf("%d",pv+i);
}

main(){
    int a[DIM] = {3,3,3,3,3}, b[DIM];
    
    VPrint(a,DIM);
    VPrintP(a,DIM);

    VRead(b,DIM);
    VPrint(b,DIM);
    
    VReadP(b,DIM);
    VPrint(b,DIM);

    printf("La somma di a e\' %d.\n",VSum(a,DIM));
    printf("La somma P di a e\' %d.\n",VSumP(&a[0],DIM));
    printf("La somma di un postfisso di a (ultimi 2 elementi) e\' %d.\n",VSum(a+2,2));
    printf("La somma P di un postfisso di a (ultimi 2 elementi) e\' %d.\n",VSumP(a+2,2));

}

ESERCIZIO

  1. Fare il "cartone animato" seguendo la metafora variabile=scatola per i programmi esempio presentati in questa sezione.
  2. Modificare i programmi visti precedentemente utilizzando, quando possibile, la dualità del C tra array e puntatori per rimpiazzare un array con il suo corrispondente puntatore.