Lo scopo di questa esercitazione e' di prendere dimestichezza gli array, una struttura dati utilizzata per memorizzare grandi quantita' di dati omogenei.

Perche' usare gli array?

Per comprendere l'utilita' degli array con un esempio pratico, ritorniamo alla simulazione del lancio di un dado vista la volta scorsa.

In particolare, scriviamo un programma che simula il lancio di N=100 dadi, e che memorizza il numero di uscite delle varie facce.


   - Invocare l'editor per il nostro programma:

     > emacs contaFacce.c &

   - Digitare il seguente testo all'interno della finestra dell'editor:

/* Programma per contare il
numero di occorrenze delle
facce di un dado in N lanci */

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

#define N 100
 
int main () {
   //dichiarazione variabili
int uno = 0, due = 0, tre = 0, quattro = 0, cinque = 0, sei = 0; \* variabili
per contare il numero di occorrenze delle varie facce *\
int esito, i;

//generazione lancio dei dadi
srand(time(NULL));//inizializza il generatore di numeri casuali

for (i=1;i <= N;i++){ //genera N lanci

esito = rand() % 6 + 1;// i-esimo lancio del dado
switch(esito) { //incrementiamo il contatore corrispondente
case 1: uno++; break;
case 2: due++; break;
case 3: tre++; break;
case 4: quattro++; break;
case 5: cinque++; break;
case 6: sei++; break;
}
}

//stampa la statistica
printf("La faccia 1 e' uscita %d volte\n",uno);
printf("La faccia 2 e' uscita %d volte\n", due);
printf("La faccia 3 e' uscita %d volte\n", tre);
printf("La faccia 4 e' uscita %d volte\n", quattro);
printf("La faccia 5 e' uscita %d volte\n", cinque);
printf("La faccia 6 e' uscita %d volte\n", sei);

return EXIT_SUCCESS;
   }


    - Compilare il sorgente:

     > gcc -ostatistica contaFacce.c

    - Eseguire il programma per vedere il valore della costante:

     > ./statistica



   Alcune osservazioni:

   1. Abbiamo usato un nuovo costrutto del linguaggio C, il comando switch. La sintassi del comando e' la seguente:

     switch (nome_variabile) {
        case val1: comando; // oppure lista di comandi
        case val2: comando; // oppure lista di comandi
        .....
        case valn: comando; // oppure lista di comandi
        //questo caso viene eseguito se il valore di nome_variabile e'
        //diverso da val1,..,valn
       
        default: comando; //oppure lista di comandi
       };

   Il comando
switch equivale ad una sequenza di comandi if, e viene utilizzato per eseguire una diversa lista di comandi a seconda del valore della variabile di controllo.

Nota:
Il caso
default e' opzionale.
Inoltre, l'ordinamento dei vari casi di un costrutto
switch e' arbitrario.
Se non specifico nessun caso di default e nessuno dei casi corrisponde al valore di
nome_variabile non viene eseguito nessun comando.
Lo stesso valore non puo' occorrere in piu' di un
case.
La variabile di controllo di un comando puo' essere di tipo
int o char. Nel caso di variabile di tipo char, il valore nei vari case va racchiuso tra apici '.

Il comando
break al termine di uno dei case serve per uscire dal costrutto; se non metto il comando break, viene eseguito il codice anche dei successivi case.

Questa caratteristica del comando
switch e' da un lato piuttosto potente, perche' permette di associare casi multipli ad un unico comando.

Esempio:

switch (esito) {
        case 1: case 3: case 5: dispari++; break; //e' uscita una faccia dispari
        case 2: case 4: case 6: pari++; break; //e' uscita una faccia pari
        };


Attenzione pero', perche' se mi dimentico di inserire il comando
break al termine di un case posso generare degli errori!!!


2. Pur utilizzando il nuovo costrutto
switch, il programma risulta un po' macchinoso:  cosa succede se dovessi tener traccia delle estrazioni del lotto (90 numeri)?

Per trattare grosse quantita' di dati di tipo omogeneo posso utilizzare gli array (vettori), che ci permettono una gestione piu' uniforme, compatta ed efficiente di questo tipo di dati.

Per convincerci di questo, riscriviamo il programma precedente facendo uso di un array per memorizzare il risultato del lancio dei dadi.

   - Invocare l'editor per il nostro programma:


     > emacs contaFacce.c &

  
- Digitare il seguente testo all'interno della finestra dell'editor:

/* Programma per contare il
numero di occorrenze delle
facce di un dado in N lanci - versione con array*/

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

#define N 100
 
int main () {
   //dichiarazione variabili
int occorrenze[6];//dichiara un vettore di 6 elementi di tipo intero
int esito, i;

//inizializzazioni
srand(time(NULL));//inizializza il generatore di numeri casuali
for (i=0;i < 6;i++)
occorrenze[i]=0;//inizializza il vettore delle occorrenze

//generazione del lancio dei dadi
for (i=1;i <= N;i++){ //genera N lanci

esito = rand() % 6;// i-esimo lancio del dado - valore compreso fra 0 e 5
occorrenze[esito]++;
}

//stampa la statistica
for (i=0; i < 6, i++){
printf("La faccia %d e' uscita %d volte\n",i+1,occorrenze[i]);
}
return EXIT_SUCCESS;
   }

Quali sono i costrutti nuovi?

La dichiarazione del vettore

<nome_tipo> <nome_vettore> [<dimensione>]

che definisce le variabili

<nome_vettore>[0]
,
<nome_vettore>[1]...
<nome_vettore>[<dimensione>-1]

tutte dello stesso tipo <nome_tipo>.

Nello specifico, il tipo è int, il nome del vettore è occorrenze, e la sua dimensione è 6.

È importante ricordarsi che la prima posizione del vettore ha indice 0, non 1!

Siccome il vettore contiene 6 elementi, l'ultimo ha indice 5, non 6!

Dopo aver definito il vettore è sempre meglio ricordarsi di inizializzarlo. A questo scopo usiamo un ciclo for che scorre gli elementi del vettore.

Non abbiamo più bisogno del costrutto switch per decidere quale variabile incrementare perché questa è determinata dal valore sotto esame:
Se 
valore==0 dobbiamo incrementare il valore dell'elemento del vettore in posizione 0
Se valore==1 dobbiamo incrementare il valore dell'elemento del vettore in posizione 1...

In pratica, se valore==i dobbiamo incrementare il valore dell'elemento del vettore in posizione i.

Infine la stampa della statistica può essere eseguita attraverso un comodissimo ciclo.

In altre parole, usando un array abbiamo reso molto piu' compatto ed efficiente il nostro programma.


    - Compilare il sorgente:

     > gcc -ostatistica contaFacce.c

    - Eseguire il programma per simulare il lancio del dado:

     > ./statistica




Esercitazione non guidata

Risolvere il seguente esercizio e spedire il solo file sorgente (suffisso .c) all'indirizzo paolo.santi@iit.cnr.it all'interno di un messaggio di posta elettronica con subject: Esercitazione Lezione 5. Nel messaggio indicare il vostro nome, cognome e gruppo di appartenenza.

1. Scrivere un programma tombola.c che simuli la costruzione di una cartella e una sessione di gioco di tombola.

Per costruire la cartella, il programma deve generare casualmente 15 numeri DIVERSI compresi tra 1 e 90, memorizzandoli in un vettore di nome cartella. Le prime cinque posizioni (da indice 0 a indice 4) costituiranno la prima riga della cartella, le seconde cinque (da 5 a 9) la seconda riga e le ultime cinque (da 10 a 14) la terga riga.

Una volta generata la cartella, il programma deve stamparla a video, producendo una scritta del tipo:


+----------------+
| 12 8 23 87 45 |
| 4 56 11 74 1 |
| 43 10 46 89 71 |
+----------------+

Infine, il programma deve simulare una sessione di gioco generando casualmente numeri compresi tra 1 e 90: ad ogni estrazione, dopo aver controllato che il numero estratto non sia gia' uscito precedentemente, bisogna verificare se il numero è presente nel vettore cartella ed eventualmente sostituirlo col valore speciale 0. Inoltre bisogna segnalare la tombola, stampando il numero totale di estrazioni necessarie per fare tombola.

Per tener traccia dei numeri usciti si consiglia di utilizzare un vettore di 90 numeri.

Si raccomanda di stampare, per ogni estrazione, sia la situazione della cartella che il numero estratto. 

Se vi trovate a vostro agio, potete usare una matrice (vettore a due dimensioni) invece di un vettore per memorizzare la cartella.



Torna alla HomePage del corso