FUNZIONI E PROCEDURE
<tipo>
<identificatore> (<lista parametri>) {
dichiarazioni
istruzioni /
comandi
(se tipo != void
deve esserci un return e con e i tipo <tipo>)
}
funzioni
= procedure che dialogano in uscita = che restituiscono un risultato
dichiarare una
funzione = associare un identificatore ad un insieme di
istruzioni
procedura /
funzione permette di assegnare un identificatore ad una serie di
comandi
posso avere
procedure semplici (non dialogano con chi le chiama = non
variano rispetto a dei parametri) o procedure che si aspettano
dei valori e che restituiscono valori
es.
int
main (void){
int
a = 1;
int
b = 2;
printf
(“%d”, a);
scrivisepara();
/* scrive *** */
printf
(“%d”, b);
scrivisepara();
}
/* scrivisepara non riceve nessun input e non restituisce nessun
valore*/
void
scrivisepara () {
for
(a = 1; a < 4; a++) printf (“*”);
printf
(“\n”);
}
ecco il funzionamento
del programma dal punto di vista ambiente-memoria:

abbiamo due
identificatori a in due moduli diversi e separati (funzione e main):
non si riferiscono alla stessa variabile ma a due variabili diverse,
pertanto quando termina la funzione scrivisepara la parte in rosso
sparisce assieme alla sua variabile a (rimane la a del main)
se voglio che vari
numero di asterischi
int
main (void){
int
a = 1;
int
b = 2;
int
N1, N2;
scanf
(“ %d”, &N1);
scanf
(“ %d”, &N2);
printf
(“%d”, a);
scrivisepara(N1);
/* passo il valore della variabile N1 */
printf
(“%d”, b);
scrivisepara(N2);
}
void
scrivisepara (int k) {
for
(a = 1; a < k + 1; a++) printf (“*”);
printf
(“\n”);
}
parametri
formali (void scrivisepara(N1)) = dichiarati per
tipo, numero e ordine nella definizione della funzione (quelli della
firma, non del prototipo)
parametri
attuali (scrivisepara (N1)) = quelli che vengono
passati alla funzione all’atto della chiamata (o invocazione)
il passaggio dei
parametri in C avviene sempre e soltanto per valore (esclusi gli
array anche se solo da un certo punto di vista)
ciò significa
che all’atto dell’invocazione di una funzione ogni
parametro formale è inizializzato con il valore del
corrispondente parametro attuale
int
fibo(int n) {
int
x, y, cont, temp;
x
= 0;
y
= 1;
cont
= 1;
for
(cont = 1; cont < n – 2; cont++){
temp
= y;
y
= x + y;
x
= temp;
}
return
y;
}
int
w, l;
l
= 55;
w
= fibo (l + 1);
int
somma (int x, int y){
return
(x + y);
}
somma = identificatore
legato ad una porzione di memoria (anche nel caso delle procedure)
nei prototipi
posso scrivere anche ad es.
int somma (int,
int);
albero delle
chiamate:

#include
<stdio.h>
int
y = 5;
void
P (int x){
printf(“
%d”, x + y);
}
int
main(){
y++:
P(4) ;
/* procedura propria */
}
stampa 10
procedura
propria = non restituisce nessun valore
#include
<stdio.h>
int
y = 5;
void
P (int x){
printf(“
%d”, x + y);
return
0 ;
}
int
main(){
int
y = 10 ;
P(4) ;
return
0 ;
}
stampa 9 non 14
poichè si riferisce sempre alla variabile globale
se
avessimo dichiarato la y nel main come static, alla
fine della procedura non sarebbe stata liberata la memoria dedicata a
tale variabile ma la sua visibilità non sarebbe cambiata
scrivere un programma
che chieda all’utente un n intero positivo e lo scriva sullo
standard output:
void
scrivi(int n);
int
main(){
int
z;
scanf(“%d”,
&z);
scrivi(z);
}
iterativo:
void
scrivi(int k){
int
i;
for
(i = -k; i < k, i++) printf(“%d”, i);
}
ricorsivo:
void
scrivi(int n){
if
(n==0) printf (“0”);
else
{
printf(“%d”,
-n);
scrivi(n
- 1);
printf(“%d”,
n);
}
}
programma che disegna
un triangolo di asterischi:
iterativo
void
scrivilinea(int n){
int
k;
for
(k = 0 ; k < n ; k++)
printf(“*”);
printf(“\n”);
}
ricorsivo
void
scrivilineaR(int n){
if
(n == 0) printf(“\n”);
else
{
printf(“*”);
scrivilineaR(n
- 1);
}
}
per fare il triangolo
iterativo
void
stelle (int n){
int
h;
for
(h = 1; h <= n; h++) scrivilinea(h);
}
ricorsivo
void
stelleR (int n){
if
(n != 0) {
stelleR(n
- 1);
scrivilineaR(n
- 1);
}
}
lo svantaggio
della ricorsività è la spesa in termini di
risorse il vantaggio è la più facile
manutenzione e la capacità di risolvere problemi grossi
partendo da problemi più piccoli
programma per il
fattoriale:
int
F (int x){
int
res;
if
(x < 2) return 1;
res
= F(x - 1);
return(res
* x) ;
}
int
main(){
int
a;
scanf(“%d”,
&a);
printf(“%d”,
F(a));
}
fibonacci ricorsivo:
int
fib(int n) {
if
(n == 0) return 0;
if
(n == 1) return 1;
return
(fib(n – 1) + fib(n - 2));
}
il problema è
che per calcolare ad esempio il 25 numero di fibonacci servono 25.000
chiamate: si può ovviare in parte a questo evitando di
ricalcolare per ogni chiamata della funzione i valori già
processati da questa (utilizzando variabili statiche)
MODO ALTERNATIVO DI SCRIVERE PIÙ PROTOTIPI
SIMILI
void
apri (void), salva (void), chiudi (void);
equivale a:
void
apri (void);
void
salva (void);
void
chiudi (void);
|