Soluzione esercizio 3

Questo esercizio presenta molti aspetti interessanti: da una parte la lettura di dati da diversi strumenti con identificatori arbitrari, dall'altra il fatto che, dopo essere stati letti ed analizzati i dati dei singoli strumenti, bisogna stamparli dopo averli messi in ordine di codice.

Dovendo fare operazioni cosí diverse, proponiamo una soluzione in cui i dati vengono organizzati nella struttura:

struct strumento {
  int codice;
  double media;
  int misure;
};
Perchè questa struttura, oltre ai dati richiesti (codice e media) contenga anche il numero di misure sarà chiaro in seguito.

In problemi di ordinamento di diversi dati rispetto ad un campo (nel nostro caso dovremmo ordinare le coppie codice-media in ordine di codice), se i dati sono immagazzinati in una struttura, basta avere in mente come si fa una funzione ordina generica, del tipo costruito in laboratorio, ed adattarla al caso specifico:

void ordina( struct strumento * vettore, int N) {
  int i, j;
  struct strumento temp;
  for (i=0; i<N-1; i++) {
    for (j=i+1; j<N; j++) {
      if ( vettore[i].codice > vettore[j].codice ) {
	temp = vettore[j];
	vettore[j]=vettore[i];
	vettore[i]=temp;
      }
    }
  }
}
Usando l'operatore di assegnazione tra strutture si automatizza la scambio delle variabili ausiliarie per l'ordinamento.

Con questi due mattoni possiamo iniziare a descrivere l'algoritmo usato per risolvere l'esercizio. Notiamo che, siccome non sappiamo il numero di righe del file di ingresso, non è possibile direttamente immagazzinare in memoria tutti i dati per poi analizzarli successivamente, ma bisogna procedere in modo tale da mantenere sempre aggiornata la lista degli strumenti con le loro medie.

Il programma

Il programma seguente segue il flusso:

  1. definizione di un vettore di strutture strumento di 100 elementi ed inizializzazione del numero di strumenti trovati (Nstrumenti) a zero;
  2. apertura del file;
  3. ciclo while con lettura di una riga alla volta del file fino alla fine;
  4. per ogni riga letta, il codice viene confrontato con quello degli strumenti già noti: si noti nel codice del programma il modo di usare un break del ciclo for per verificare se lo strumento è stato trovato o no, come pure la formula per aggiornare la media (che ha bisogno appunto di sapere quante misure sono già state mediate).
  5. si chiude il file di ingresso;
  6. il vettore di strumenti viene ordinato usando la funzione ordina;
  7. si apre il file di uscita;
  8. per ogni strumento si scrive codice e media;
  9. si chiude il file di uscita e si termina il programma.

#include <stdio.h>

#define MAX_STRUMENTI 100

int main() {
  /* Dichiarazione del vettore di strumenti. */
  struct strumento strumenti[MAX_STRUMENTI];
  int Nstrumenti=0;
  int i, codice;
  double lettura;
  FILE* f;
  /* Apertura del file di ingresso. */
  f=fopen("rilevazioni.dat","r");
  /* Ciclo di lettura del file. */
  while ( fscanf(f,"%d %lf",&codice,&lettura)!=EOF) {
    /* si confronta il codice letto con quello 
       degli strumenti già incontrati.   */
    for (i=0; i<Nstrumenti; i++) {
      if ( codice==strumenti[i].codice ) {
	/* Se lo strumento viene trovato, la media viene aggiornata.
	   Osservare la formula: non c'è bisogno di immagazzinare
	   i dati e fare la media successivamente.
	*/
	strumenti[i].misure++;
	strumenti[i].media=
          (1-1./strumenti[i].misure)*strumenti[i].media
	  +lettura/strumenti[i].misure;
	/* ...ed è inutile continuare il ciclo.
           in questo modo usciamo dal ciclo con i pari alla
           posizione dello strumento nel vettore.           */
	break;
      }
    }
    /* Se lo strumento non è stato trovato, all'uscita
       del ciclo i vale Nstrumenti, allora inseriamo di dati del
       nuovo strumento ed incrementiali il numero degli strumenti
       conosciuti                                                 */
    if (i==Nstrumenti) {
      strumenti[Nstrumenti].codice=codice;
      strumenti[Nstrumenti].media =lettura;
      strumenti[Nstrumenti].misure=1;
      Nstrumenti++;
    }
  }
  /* Chiusura del file di ingresso. */
  fclose(f);
  /* Ordinamento del vettore di strumenti. */
  ordina(strumenti,Nstrumenti);
  /* Apertura del file di uscita. */
  f=fopen("output.dat","w");
  /* Stampa dei dati. */
  for ( i=0; i<Nstrumenti; i++) 
    fprintf(f,"%d %lf\n",strumenti[i].codice,strumenti[i].media);
  /* Chiusura del file di uscita e termine del programma. */
  fclose(f);
  return 0;
}