Sezione 2.3 Funzioni (II). |
||
![]() |
int x=5, y=3, z;In questo caso viene richiamata la funzione somma passandogli i valori di x ed y , ossia 5 e 3 , ma non le variabili stesse:
z = somma ( x , y );
In questo modo, quando la funzione somma è chiamata, i valori delle sue variabili a e b sono 5 e 3 rispettivamente. Una modifica di a o b all'interno della funzione somma non cambia i valori delle variabili x ed y esterne ad essa. Questo perché non sono state passate le variabili x ed y alla funzione somma ma soltanto il loro valore .
Ci sono però casi in cui vogliamo modificare dall'interno di una funzione il valore di variabili definite esternamente alla funzione stessa. A questo scopo possiamo usare dei parametri passati per riferimento, come nella funzione raddoppia dell'esempio seguente:
// passaggio di parametri per riferimento |
x=2, y=6, z=14 |
La prima cosa da notare è che nella dichiarazione di raddoppia il tipo di ciascun parametro è seguito dal carattere e commerciale (&); esso sta ad indicare appunto un passaggio di parametro per riferimento invece dell'usuale passaggio per valore .
Quando passiamo una variabile per riferimento è la variabile stessa che noi passiamo alla funzione e non soltanto il suo valore. Di conseguenza una modifica del valore del parametro all'interno della funzione modifica il valore della variabile passata come parametro.
In altre parole noi abbiamo associato le variabili locali a , b e c (i parametri formali della funzione) alle variabili x , y e z (i parametri attuali passati nella chiamata alla funzione) in modo tale che a diventa sinonimo di x , b sinonimo di y e c sinonimo di z . Ricordando che una variabile è il nome di una zona di memoria in cui può essere memorizzato un valore (il valore della variabile appunto), dire che a e x sono sinonimi significa che essi sono nomi diversi per la stessa zona di memoria. Se a ed x sono sinonimi, una modifica del valore di a ha come conseguenza la modifica del valore registrato nella zona di memoria comune ad a e x e dunque anche il valore di x cambia.
Ecco perché l'output del nostro programma, che stampa i valori delle tre variabili x, y e z , mostra che i valori di tali tre variabili sono raddoppiati dopo la chiamata alla funzione raddoppia .
Se avessimo dichiarato la funzione raddoppia senza il simbolo e commerciale (&):
void raddoppia (int a, int b, int c)non avremmo passato le variabili x, y e z ma soltanto i loro valori e quindi il programma avrebbe stampato i valori di x , y e z non modificati.
Il passaggio di parametri per riferimento permette di scrivere funzioni
che calcolano più di un valore. Ad esempio, ecco una funzione
che calcola il numero precedente ed il numero successivo del primo
parametro che gli viene passato:
// calcolo di piu' di un valore |
Precedente=99, Successivo=101 |
// valori di default per i parametri |
6 5 |
Nel programma precedente ci sono due chiamaste alla funzione dividi. Nella prima:
divide (12)viene passato un solo argomento mentre la funzione ne richiede due. Siccome il secondo parametro ha valore di default 2 è proprio il valore 2 che viene passato implicitamente come valore del secondo parametro b. Quindi il risultato che si ottiene è 6 (12/2 ).
dividi (20,4)vi sono entrambi i parametri, quindi il valore di default 2 non viene usato ma viene passato il valore 4 come valore del secondo parametro b . Quindi il risultato che si ottiene è 5 ( 20/4 ).
// funzione sovraccaricata |
2 2.5 |
In questo caso abbiamo definito due funzioni con lo stesso nome dividi ma con parametri di tipo diverso: la prima con due parametri di tipo int, la seconda con due parametri di tipo float. Il compilatore decide quale delle due debba essere chiamata esaminando il tipo dei parametri attuali forniti nella chiamata.
Nell'esempio le due funzioni hanno lo stesso corpo ma questo non è necessario: funzioni con lo stesso nome possono anche fare cose completamente diverse.
n! = n * (n-1) * (n-2) * (n-3) ... * 1si può definire induttivamente nel seguente modo:
// calcolo del fattoriale |
Dammi un numero:9 9! = 362880 |
Osserviamo che nella funzione fattoriale viene ricorsivamente effettuata una chiamata alla funzione fattoriale stessa. La chiamata ricorsiva viene però effettuata soltanto se l'argomento è maggiore di 1 , altrimenti la funzione entrerebbe in un ciclo di ricorsione infinito , venendo richiamata con argomento 0 e quindi con argomento -1 , -2 e così via.
Un'altra osservazione è che la funzione fattoriale ha una limitazione nei valori dell'argomento dovuta al fatto che il fattoriale di un intero cresce molto rapidamente. In pratica, il tipo del risultato (long) non permette di memorizzare fattoriali maggiori di 12!.
La forma di una dichiarazione di prototipo è la seguente :
tipo none ( tipo_parametro1, tipo_parametro2, ...);ed è simile alla intestazione di una dichiarazione di funzione eccetto:
// prototipazione |
Scrivi un numero (0 per uscire): 9 Il numero è dispari. Scrivi un numero (0 per uscire): 6 Il numero è pari. Scrivi un numero (0 per uscire): 1030 Il numero è pari. Scrivi un numero (0 per uscire): 0 Il numero è pari. |
Questo esempio non ha una grande utilità: chiunque sarebbe in grado di ottenere lo stesso risultato con un programma molto più semplice. Ma lo scopo dell'esempio è illustrare come funziona la prototipazione. Inoltre, in questo caso la prototipazione di almeno una delle due funzioni dispari e pari è indispensabile in quanto le due funzioni si richiamano vicendevolmente.
All'inizio del programma compaiono i prototipi delle funzioni dispari e pari:
void dispari (int a);che permettono di usare le due funzioni prima che esse siano completamente definite, ad esempio in main che adesso può essere messo nella posizione più logica, cioè all'inizio del programma.
void pari (int a);
Molti programmatori esperti consigliano di prototipare tutte le funzioni. Questo è particolarmente utile quando un programma contiene molte funzioni o le definizioni delle funzioni sono molto lunghe. In tal caso raccogliere tutti i prototipi nello stesso posto all'inizio facilita la ricerca se non si ricorda come devono essere richiamate (numero e tipo dei parametri).
![]() |
![]() 2-2. Funzioni (I). |
![]() indice |
![]() 3-1. Array. |