Sei sulla pagina 1di 13

Il generatore di numeri casuali

file di libreria: stdlib.h

int rand(void)

La funzione restituisce un numero casuale di tipo intero compreso tra 0 e RAND_MAX (estremi compresi)

Esempio: scriviamo un programma che permetta di generare un numero casuale; facciamo poi in modo che il
numero casuale sia compreso all’interno di un prefissato intervallo.

#include <stdio.h> // per la funzione printf()


#include <stdlib.h> // per la funzione rand()

int main()
{int casuale;
casuale = rand() /* il numero casuale viene generato ed il suo valore viene salvato in casuale
casuale risulta compreso tra 0 e RAND_MAX. E se vogliamo che sia compreso tra 30 e 70 ?
Posso pensare di ottenere questo risultato sommando a 30 un numero casuale compreso
tra 0 e 40 (ovvero 70 - 30 ) */
casuale=30 + rand()%41; // Il resto di una divisione per 41 al massimo vale 40

// avendo usato l’operatore resto, questo procedimento si può usare solo con le variabili di tipo int

return 0;}
Implementiamo una funzione che serva a generare valori casuali, di tipo intero, compresi tra un valore massimo ed
un valore minimo; valore massimo e minimo devono essere scelti al momento della chiamata alla funzione.

// prima versione

int IntCasuale(int,int); // 2 parametri per scegliere minimo e massimo, 1 valore intero da restituire

int IntCasuale(int minimo,int massimo)


{int numero;
numero=rand()%(massimo-minimo+1)+minimo;
return numero;}

// seconda versione

int IntCasuale(int,int); // 2 parametri per scegliere minimo e massimo, 1 valore intero da restituire

int IntCasuale(int minimo,int massimo)


{ // restituisco il valore non appena esso viene generato
return rand()%(massimo-minimo+1)+minimo;
}
Implementiamo una funzione che serva a generare valori casuali, di tipo float, compresi tra un valore massimo ed un
valore minimo; valore massimo e minimo devono essere scelti al momento della chiamata alla funzione.

Se min e max rappresentano gli estremi dell’intervallo a cui devono appartenere i numeri casuali ...

La matematica ci insegna che, dato un numero casuale, x, compreso tra 0 e RAND_MAX

y = (x/RAND_MAX) * (max-min) + min;


compreso tra min e max

compreso tra 0 e 1 compreso tra 0 e (max-min)

Trovare l’errore ...

float FloatCasuale(float,float); // 2 parametri per scegliere minimo e massimo, 1 valore float da restituire

float FloatCasuale(float minimo,float massimo)


{
return (rand()/RAND_MAX)*(massimo-minimo) + minimo;
}
Costrutti iterativi: for e while

for(inizio ; continuazione ; finale ) inizio: espressione valutata prima di iniziare il ciclo


{ istruzioni } continuazione: espressione valutata prima di ogni iterazione
quando essa risulta falsa le istruzioni non vengono eseguite
finale: espressione valutata dopo l’esecuzione delle istruzioni

while( continuazione ) continuazione: espressione valutata prima di ogni iterazione


{ istruzioni } quando essa risulta falsa le istruzioni non vengono eseguite

Per terminare l’esecuzione di uno dei due cicli, usare l’istruzione

break;

for(inizio ; continuazione ; finale ) i costrutti sono equivalenti inizio;


{ istruzioni } while( continuazione )
{ istruzioni
finale; }
Implementiamo un programma che permetta di generare un numero prefissato di valori casuali.

Il programma deve richiamare la funzione IntCasuale(int,int) per generare valori interi casuali compresi tra -10 e 10

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

int IntCasuale(int,int);

int main()
{int casuale,i;

for(i=0 ; i<50 ; i=i+1) // i rientri nel codice favoriscono la leggibilità del


{casuale=IntCasuale(-10,10); // codice stesso
printf(“Ecco il numero casuale numero %d: %d\n”,i,casuale);
}

return 0;}

int IntCasuale(int min,int max)


{return rand()%(max-min+1)+min;

Facciamo in modo di poter utilizzare la funzione IntCasuale() da un qualsiasi programma ... ->
Separiamo il testo del codice:
funzioni.h contiene prototipo ed implementazione della funzione, oltre alle direttive per il preprocessore che
permettono l’utilizzo di funzioni di libreria richiamate dalla funzione

casuale.c contiene il testo del programma vero e proprio, chiamate alle funzioni e le direttive per il preprocessore
che permettono l’utilizzo di funzioni di libreria chiamate dalla funzione main()

casuale.c funzioni.h

#include “funzioni.h”
#include <stdio.h>
#include <stdlib.h>
int main()
{int casuale,i; int IntCasuale(int,int);

for(i=0 ; i<50 ; i=i+1)


{casuale=IntCasuale(-10,10); int IntCasuale(int min,int max)
printf(“Ecco il numero casuale numero %d: %d\n”,i,casuale); {return rand()%(max-min+1)+min;
}

return 0;}

Così facendo, a patto di includere il file funzioni.h, da un qualsiasi codice sarà possibile effettuare chiamate alla
funzione IntCasuale()
Ricordiamoci che il costrutto for() valuta delle espressioni ...

#include “funzioni.h” #include “funzioni.h”


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

int main() int main()


{int casuale,i; {int i;

for(i=0 ; i<50 ; i=i+1) for(i=0 ; i<50 ; printf(“numero %d: %d\n”,i, IntCasuale(-10,10));)


{casuale=IntCasuale(-10,10); {
printf(“numero %d: %d\n”,i,casuale); i=i+1;
} }

return 0;} return 0;}

#include “funzioni.h” #include “funzioni.h”


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

int main() int main()


{int i; {int i;

for(i=0 ; i<50 ; i=i+1) for(i=0;i<50 ;printf(“numero %d:%d\n”,i++, IntCasuale(-10,10));)


{ {; }
printf(“numero %d: %d\n”,i, IntCasuale(-10,10)); return 0;}
}

return 0;}
La direttiva #define

La direttiva #define appartiene al gruppo di istruzioni che permettono di gestire l’azione del preprocessore.
Tale direttiva permette di definire una MACRO, ovvero un’etichetta, un simbolo, e di assegnare a tale MACRO un
valore; ogni volta che il preprocessore incontra la MACRO nel codice, esso sostituisce alla MACRO il valore scelto dal
programmatore. Il valore della MACRO viene INSERITO al posto della MACRO stessa, senza alcun controllo.

DOPO la sostituzione, sarà poi il compilatore ad analizzare il codice ed a verificarne la correttezza sintattica.

#define INTERO 30
#define CIAO printf(“ciao, questa frase l’ho scritta con una MACRO!\n”);

int main() macro.c


{int i;

CIAO // NOTA: il ‘;’ è già inserito nella MACRO, non serve indicarlo qui!
i=INTERO;

return 0;}

Scriviamo questo codice e poi compiliamo con il comando

gcc –E macro.c

cosa risulta?
Nel caso in cui il testo della MACRO fosse particolarmente lungo ... possiamo andare a capo.

#include <stdio.h>
#define LONG_MACRO printf(“Questa MACRO viene definita usando varie righe;\n”); \
printf(“per la definizione e’ sufficiente inserire alla fine di ogni riga\n”); \
printf(“un carattere speciale: \\ \n”);

int main()
{LONG_MACRO
return 0;}

La MACRO può essere definita all’atto della compilazione

direttiva.c
#include <stdio.h> Al momento della compilazione usare il comando:

int main()
{int i; gcc –o direttiva –Wall –DVALORE=5 direttiva.c
i=VALORE;
printf(“Il valore di i risulta: %d\n”,i);
return 0;} L’opzione –D indica che si sta per definire una macro
Subito dopo D, SENZA SPAZI, va indicato il nome della macro
e poi il suo valore
La cosa può tornare utile, ad esempio, per inizializzare il generatore di numeri casuali.

La libreria standard include un generatore di numeri casuali, rand(); la funzione genera numeri casuali a partire da un
valore iniziale fissato dalla libreria stdlib.h.

VALORE INIZIALE nuovo valore nuovo valore nuovo valore

algoritmo algoritmo algoritmo

Se il primo valore, il SEME, rimane costante, allora la sequenza sarà sempre la stessa. Per cambiare il seme, si può usare
la funzione

void srand(int);

il parametro rappresenta il valore del seme

#include <stdio.h> inizio.c


#include <stdlib.h>

int main()
{int i; gcc –o inizio –Wall –DINIZIO=50 inizio.c
srand(INIZIO);
i=rand();
printf(“Il valore di i risulta: %d\n”,i);
return 0;}
Implementiamo un costrutto che ci permetta di pulire il buffer di input e trasformiamolo in una MACRO

#include <stdio.h>

int main()
{char carattere;
printf(“Inserisci un carattere: “);
carattere=getchar();

// per eliminare eventuali altri caratteri chiamo la funzione getchar() fino a quando trovo LF

while(carattere!=10)
{carattere=getchar();}

return 0;}

#include <stdio.h>

int main()
{char carattere;
printf(“Inserisci un carattere: “);
carattere=getchar();

// per eliminare eventuali altri caratteri chiamo la funzione getchar() fino a quando trovo LF

while(getchar()!=10) {;} // analizzo il valore, senza assegnarlo ad alcuna variabile

return 0;}
Implementiamo un costrutto che ci permetta di pulire il buffer di input e trasformiamolo in una MACRO

#include <stdio.h>
#define CLEAN_BUFFER while(getchar()!=10) {;}

int main()
{char carattere;
printf(“Inserisci un carattere: “);
carattere=getchar();

CLEAN_BUFFER // non serve il ; !

return 0;}

La definizione della MACRO può essere inserita nel file funzioni.h,


in modo da poterla richiamare da un qualsiasi file in cui sia necessario
effettuare la pulizia del buffer di input.
Esercizi proposti

(1) Implementare una funzione che non accetti alcun parametro e che restituisca un valore di tipo int. La
funzione deve generare un numero intero di tipo casuale compreso tra 97 e 122, estremi inclusi. Fatto questo
la funzione deve restituire tale valore casuale. NOTA: gli estremi dell’intervallo in cui devono cadere i numeri
casuali vanno definiti come MACRO

(2) Scrivere un programma in cui venga chiesto all’utente di inserire un carattere da tastiera; una volta che
l’utente ha inserito il carattere, il programma deve confrontare tale carattere con quello generato usando la
funzione definita al punto precedente. Visualizzare un messaggio in modo tale che l’utente sappia se ha
indovinato quale sia il carattere generato casualmente o meno; in particolare visualizzare sia il carattere
inserito dall’utente che quello generato dalla funzione.

(3) Scrivere un programma simile al precedente, ma in cui l’utente possa effettuare più tentativi per indovinare
quale sia il carattere generato in modo casuale; dopo ogni tentativo, all’utente deve essere chiesto se intenda
effettuare un nuovo tentativo o meno.
Per implementare questo programma servirsi del costrutto for(); per la terminazione del ciclo servirsi
dell’istruzione break

(4) Scrivere un programma simile al precedente servendosi del costrutto while(), per la terminazione del ciclo
NON servirsi dell’istruzione break

(5) Scrivere un programma che svolga le stesse operazioni di quello descritto al punto (3) servendosi di una
funzione implementata in modo ricorsivo