Lettura array da file

Vediamo ora un esercizio sugli array dinamici. Si tratta semplicemente di riscrivere l'esercizio di lettura di array da file, in cui l'array viene rappresentato con una struttura invece che con tre variabili separate che indicano il vettore stesso, la sua dimensione, e il numero di elementi usati.

Il programma inizia con una allocazione iniziale dell'array: vengono allocati 100 elementi, e quindi la variabile che indica la dimensione viene aggiornata. In questo momento l'array contiene 100 elementi, ma nessuno è stato ancora letto: possiamo quindi dire che nessuno di questi cento elementi è usato per rappresentare un valore significativo.

Il programma prosegue controllando se è stato lanciato con il numero giusto di argomenti, e in caso affermativo apre il file il cui nome è stato passato come argomento.

Vediamo ora più in dettaglio il ciclo di lettura:

                        /* ciclo di lettura */
  i=0;
  while(1) {
    res=fscanf(fd, "%d", &a.punt[i]);
    if( res!=1 )
      break;

    if(a.n<i+1)
      a.n=i+1;

    i++;

    if(i>a.dim-1) {
      a.dim+=100;
      a.punt=realloc(a.punt, a.dim*sizeof(int));
    }
  }

Usiamo una variabile i per scandire l'array. Dal momento che il primo elemento letto è quello di indice zero, questa variabile parte da zero.

Si inizia poi il ciclo: si legge un elemento dell'array, e se la cosa non riesce si esce dal ciclo. Se l'elemento a.punt[i] è stato letto con successo, allora l'elemento del vettore di indice i contiene un valore significativo, quindi il vettore ora ha i+1 elementi significativi (di indice da 0 a i). Dal momento che il valore a.n deve rappresentare il numero di elementi significativi dell'array, va aggiornato se è inferiore a i+1.

A questo punto, si aumenta il valore dell'indice i per prepararsi alla lettura del prossimo elemento. L'elemento che verrà letto al prossimo ciclo à a.punt[i]. Non è detto però che questo elemento sia stato già allocato. Quindi, occorre controllare se il vettore ha abbastanza elementi allocati. Dal momento che nel vettore ci sono a.dim elementi allocati, allora questi hanno indici 0, 1, ..., a.dim-1. Se i è al di fuori di questo intervallo, ossia i>a.dim-1, allora va fatta una nuova allocazione di memoria.

A volte è possibile che ci sia confusione su quando mettere il -1 e quando no. La regola generale da seguire è che i primi x elementi di un vettore hanno indici 0, 1, ..., x-1. Se quindi voglio sapere se l'indice i si trova fra i primi x elementi del vettore, devo controllare se si trova in quell'intervallo.

Il programma completo leggiarray.c è riportato qui sotto.

/*
  Legge da file un array dinamico,
che viene rappresentato come struttura.
*/

#include<stdlib.h>
#include<stdio.h>


/* la struttura che contiene il vettore dinamico,
la sua dimensione, e il numero di elementi effettivamente
usati */

struct ArrayDinamico {
  int *punt;
  int dim;
  int n;
};


/* stampa un vettore dinamico su schermo */

void StampaVettore(struct ArrayDinamico x) {
  int i;

  for(i=0; i<=x.n-1; i++)
    printf("%d ", x.punt[i]);

  printf("\n");
}


/* main */

int main(int argn, char *argv[]) {
  FILE *fd;
  int res;

  struct ArrayDinamico a;
  int i;


			/* inizializza l'array */
  a.dim=100;
  a.punt=malloc(a.dim*sizeof(int));
  a.n=0;		/* non ho letto nessun elemento finora */


			/* controllo argomenti */
  if( argn-1 < 1 ) {
    printf("Manca il nome del file che contiene il vettore\n");
    exit(1);
  }


			/* apre il file */
  fd=fopen(argv[1], "r");
  if( fd==NULL ) {
    perror("Errore in apertura del file");
    exit(1);
  }


			/* ciclo di lettura */
  i=0;
  while(1) {
    res=fscanf(fd, "%d", &a.punt[i]);
    if( res!=1 )
      break;

    if(a.n<i+1)
      a.n=i+1;

    i++;

    if(i>a.dim-1) {
      a.dim+=100;
      a.punt=realloc(a.punt, a.dim*sizeof(int));
    }
  }


			/* chiude il file */
  fclose(fd);


			/* stampa il vettore */
  StampaVettore(a);

  return 0;
}