PROGRAMMIAMO
C++ - Chiamata a una funzione
Passaggio di parametri per valore

Consideriamo come semplice esempio un programma che utilizza una funzione di nome eleva per il calcolo dell'elevamento a potenza con esponente intero e positivo. Il codice è il seguente:

#include <cstdlib>
#include <iostream>

using namespace std;

double eleva(double base, int esp);

int main(int argc, char *argv[])
{
double b,p;
int e;

cout<<"Inserisci il valore della base: ";
cin>>b;
cout<<"Inserisci il valore dell'esponente: ";
cin>>e;

p = eleva(b,e);

cout<<b<<" elevato a "<<e<<" = "<<p<<"\n";

system("PAUSE");
return EXIT_SUCCESS;
}

double eleva(double base, int esp)
{
double ris=1;

while (esp>0)
{
ris = ris * base;
esp--;
}

return ris;
}

Analizziamo ora nel dettaglio il funzionamento del programma. Il main acquisisce i valori delle variabili b ed e da tastiera:

cout<<"Inserisci il valore della base: ";
cin>>b;
cout<<"Inserisci il valore dell'esponente: ";
cin>>e;

Tali valori vengono quindi passati alla funzione al momento della chiamata. Essi sono in un certo senso i dati di ingresso (input) della funzione:

p = eleva(b,e);

La chiamata alla funzione trasferisce il controllo dell'esecuzione dal main alla funzione. In altre parole, l'esecuzione del programma non prosegue in sequenza ma viene effettuato un salto (jump in inglese) al codice della funzione. In un certo senso, l'esecuzione del main viene sospesa al momento della chiamata e il computer prosegue eseguendo la funzione.

La posizione dei due argomenti b ed e all'interno delle parentesi nella chiamata è molto importante, poiché al momento della chiamata il contenuto della variabile b viene copiato nel primo parametro della funzione (base), mentre il contenuto di e viene copiato nel secondo parametro (esp):

Questo meccanismo automatico per mezzo del quale il main passa dei valori alla funzione viene detto passaggio di parametri per valore. Le variabili sorgenti (quelle del main, b ed e nel nostro esempio) si dicono argomenti della chiamata, mentre le variabili di destinazione (base ed esp) vengono dette parametri della funzione.

Durante la chiamata, il valore degli argomenti viene copiato all'interno dei parametri della funzione in base alla loro posizione: il primo argomento viene copiato nel primo parametro, il secondo nel secondo e così via.

 

Variabili locali

E' importante sottolineare il fatto che b ed e sono due variabili del main, mentre base e esp sono due variabili della funzione. Più precisamente si dice che b ed e (e anche p) sono variabili locali al main, mentre base, esp e ris sono variabili locali alla funzione.

Come suggerisce il nome, le variabili locali sono variabili interne, private e utilizzabili soltanto all'interno del sottoprogramma dove sono state dichiarate. Per esempio non potrei, nel nostro esempio, scrivere nel main una cosa tipo:

cout<<"Il risultato è "<< ris;

Perché ris è una variabile locale (dichiarata all'interno) della funzione eleva. Se provo ad usare ris nel main, il compilatore mi visualizza un messaggio "ris undeclared", proprio come se ris non fosse stata dichiarata. Ma in effetti è proprio così: ris è stata dichiarata nella funzione, per il main non esiste. Allo stesso modo all'interno della funzione eleva non sarebbe possibile per esempio usare p, che è una variabile locale al main.

La chiamata alla funzione non fa eccezione a questa regola, infatti il main usa b ed e, che sono sue variabili locali:

p = eleva(b,e);

Invece la funzione riceve i valori in base ed esp, che sono le sue variabili locali:

double eleva(double base, int esp)

In pratica la funzione riceve una copia del contenuto delle variabili locali del main attraverso i propri parametri. In questo modo la funzione non ha accesso diretto alle variabili del main e non può in alcun modo modificarle.

 

Valore di ritorno

Se osserviamo ora il codice della funzione, notiamo che essa è in pratica un piccolo programma, completo delle proprie istruzioni e delle proprie variabili.

double eleva(double base, int esp)
{
double ris=1;

while (esp>0)
{
ris = ris * base;
esp--;
}

return ris;
}

A proposito di variabili, notiamo che base, esp e ris sono tutte variabili locali alla funzione. L'unica differenza fra le tre è che base e esp sono anche parametri della funzioni (vengono dichiarate fra le parentesi): in questo modo il loro valore viene inizializzato al momento della chiamata col valore dei corrispondenti argomenti del main. ris è invece una normale variabile locale, che non viene inizializzata dall'esterno (e infatti viene dichiarata all'interno del corpo della funzione).

Un'altra cosa interessante da osservare è che la funzione decrementa il valore di esp nel ciclo, finché questo non diventa zero. Siccome però esp è una variabile locale alla funzione, l'azzeramento di esp non ha nessun effetto sui valori delle variabili del main. in altre parole, esp viene azzerata, ma la variabile e del main continua a conservare il proprio valore. Come si è detto, la funzione non può in alcun modo modificare le variabili del main, nemmeno di quelle che le vengono passate con una chiamata (la funzione può invece modificare liberamente le proprie copie di tali variabili).

La funzione termina con l'istruzione

return ris;

Questa istruzione ha in un certo senso l'effetto opposto rispetto al passaggio dei parametri. In questo caso il valore contenuto in ris (variabile locale alla funzione) viene ritornato indietro al programma chiamante, il main (si parla appunto di valore di ritorno). Il valore di ritorno rappresenta dunque l'uscita (output) della funzione.

Il valore di ritorno può essere una variabile (come in questo esempio) oppure un valore numerico costante o ancora il risultato del calcolo di una espressione matematica. Per esempio i seguenti return sono tutti corretti in C:

return num;

return a+b*c;

return 2.35;

In tutti i casi però il tipo del valore di ritorno deve corrispondere col tipo della funzione (nel nostro caso la funzione è double e infatti anche la variabile ris è stata dichiarata di tipo double):

L'istruzione ris ha dunque un duplice effetto:

Il main copia il valore di ritorno della funzione nella propria variabile locale p:

p = eleva(b,e);

In questo modo il risultato del calcolo della funzione viene alla fine trasferito all'interno di una variabile locale del main.

E' importante notare che, mentre i parametri di una funzione possono anche essere molti, il valore di ritorno è invece sempre uno o uno solo (oppure nessuno, come vedremo meglio nella prossima puntata). In questo senso le funzioni sono asimmetriche, in quanto possono elaborare anche molti dati di ingresso (parametri) ma forniscono un solo risultato (valore di ritorno):

Chiamata a una funzione

Il meccanismo della chiamata a una funzione può forse sembrare un po' complicato agli inizi, ma esso è stato inventato per mettere in comunicazione due "mondi" separati: da una parte il programma main (con le proprie variabili), dall'altra la funzione (che è essa stessa un programma, dotato di variabili).

Chi scrive la funzione, non deve assolutamente preoccuparsi di come sarà scritto il main e viceversa. Nessuno ha bisogno di sapere come si chiamano le variabili dell'altro e non c'è mai il rischio che una funzione, magari male scritta, possa inavvertitamente modificare o cancellare le variabili del main o viceversa.

Il meccanismo è estremamente potente e consente ai programmatori di sviluppare le loro funzioni liberamente, senza in alcun modo dipendere da chi userà tali funzioni. Anzi, come abbiamo già visto in precedenza, le stesse funzioni possono essere usate senza problemi in molti programmi diversi. Ciò è possibile proprio grazie alla netta separazione esistente in C fra main e funzione.

 

link precedente - successiva

Sito realizzato in base al template offerto da

http://www.graphixmania.it