Cosa e' una funzione
in C
I
comandi che compongono un programma possono essere visti come azioni
elementari organizzate per assolvere un determinato compito. Spesso
capita di dover riscrivere le stesse sequenze di istruzioni in
più punti dello stesso programma, o di doverle utilizzare in
programmi diversi. Inoltre tali sequenze realizzano spesso un preciso
compito logico, anche complesso, che costituisce un vero e proprio
sottoprogramma (esempio la stampa
della cartella
nell'esercizio della tombola).
Abbiamo del resto visto che, quando bisogna scrivere
un programma per risolvere un problema complesso, e' buon uso scomporre
il problema in sottoproblemi piu' semplici. In linea di principio, i
sottoproblemi possono essere risolti da appositi sottoprogrammi, che
vengono poi combinati fra loro per risolvere il problema complesso
all'interno del programma principale
(main).
In C i sottoprogrammi vengono chiamati funzioni e, da un punto di vista logico, si comportano esattamente come le funzioni matematica: dati uno o piu' argomenti, una funzione C restituisce valore di ritorno (eventualmente vuoto).
Le librerie che abbiamo usato nelle lezioni precedenti non sono altro che collezioni di funzioni (esempio sqrt, abs, printf, etc.). Anche main è una funzione, che e' associata al programma principale.
Per poter essere utilizzata, una funzione deve essere:
- dichiarata
fornendo il cosiddetto prototipo
di funzione (prima del main)
- definita (dopo il main)
Vediamo un esempio di programma che sfrutta una funzione per leggere
valori interi
compresi in un certo intervallo:
/* |
Nota Bene: In C, sia gli argomenti passati alla funzione che il risultato dell'esecuzione di una funzione devono essere di un certo tipo di dato. I tipi di dato sia degli argomenti che del risultato sono dichiarati nel prototipo della funzione.
Nota Bene: Se una funzione non
deve restituire nessun risultato, deve essere dichiarata di tipo void.
Nell'esempio sopra riportato, la funzione leggi ha due argomenti di tipo int, e restituisce un
risultato di tipo int.
Nella definizione della funzione (dopo il main), assegno un nome ai parametri (x e y), nome che viene utilizzato all'interno della
definizione di funzione per elaborare il risultato della funzione
stessa.
Funzioni
Iterative e Ricorsive
Nelle esercitazioni precedenti abbiamo
usato i cicli (costrutti
while, do_while e for) per ripetere
più volte
l'esecuzione di un certo gruppo di comandi, magari sfruttando alcuni
indici che ad ogni iterazione assumevano
valori diversi in modo
da ripetere l'esecuzione dei comandi su porzioni differenti dei dati
(ad esempio, le celle di un array).
Le funzioni basate sull'uso di questi costrutti vengono chiamate funzioni iterative.
Le funzioni iterative sono potenti, largamente applicabili, spesso efficienti ma possono risultare artificiose, poco leggibili e quindi difficili da comprendere.
Per molte classi di problemi, una
valida alternativa alla definizione
di funzioni iterative è offerta dalla natura
ricorsiva del problema
stesso. In questi casi possiamo
rimpiazzare le funzioni iterative con funzioni
ricorsive,
Cosa
e' una funzione ricorsiva? Una funzione ricorsiva e' una
funzione che, all'interno della sua definizione, invoca se stessa (con
argomenti diversi).
Le funzioni ricorsive sono solitamente
eleganti, sintetiche, di
immediata comprensione, ma bisogna stare attenti a non abusarne.
Infatti, sono meno efficienti delle
funzioni iterative, perche' la stessa funzione viene invocata
molte volte, ed ogni invocazione di una funzione "costa".
Inoltre, bisogna stare attenti a definire
correttamente le funzioni ricorsive, altrimenti rischio di
generare un ciclo infinito nell'esecuzione del programma!!!!
L'esempio classico per illustrare la differenza tra funzioni iterative e ricorsive è quello del fattoriale di un numero.
Calcolo
del Fattoriale di un numero
Definizione iterativa: Il fattoriale n! di un intero n maggiore o uguale a 2 è definito come:
ovvero il fattoriale di n si ottiene a partire dal fattoriale di n-1, moltiplicando per n.
Il prototipo della funzione è indipendente dalla realizzazione: il fattoriale deve ricevere un intero come argomento e deve restituire un intero:
int fat(int);Analogamente il main si limiterà ad usare (invocare) la funzione, senza preoccuparsi di come venga implementata:
int main () {
int numero;
printf("Immetti un numero maggiore o uguale a 0: ");
scanf("%d",&numero);
printf("%d! = %d\n",numero,fat(numero));
return EXIT_SUCCESS;
}
La definizione della funzione fat sarà invece diversa a seconda della scelta realizzativa:
|
|
Attenzione: Le due versioni non possono
essere inserite assieme
nello stesso file perché definiscono funzioni con lo stesso
nome.
Esercitazione non guidata
Da fare subito!!
Scrivere un programma che, dato un numero intero positivo n, calcola
l'n-esimo numero di Fibonacci Fib(n).
Il programma deve utilizzare una funzione ausiliaria calcola_fib per calcolare l'n-esimo numero di Fibonacci. Si richiedono due diverse versioni della funzione ausiliaria calcola_fib, una ricorsiva e l'altra iterativa.