Sei sulla pagina 1di 5

I.T.I.S. A.ROSSI A.S. 2011/2102 Materia: SISTEMI DISPENSA C++ Prof. M.

DJANIC

DICHIARAZIONE DI RIFERIMENTO, PASSAGGIO PER VALORE & PASSAGGIO PER RIFERIMENTO Cos' un riferimento? Prima di tutto parliamo di riferimenti al di fuori del contesto delle funzioni. Facciamo un passo indietro e chiediamoci cosa significa fare una dichiarazione di variabile. Ad esempio:
int x;

Una dichiarazione di variabile dichiara una locazione di memoria (un contenitore) in cui collocare (memorizzare) i dati. A tale contenitore stato dato il nome x. Consideriamo ora la seguente dichiarazione di riferimento:
int& y=x;

(scritto anche:

int &y=x;

con la quale si dichiara che y un riferimento (si noti il carattere speciale &). Cosa significa? Significa che i nomi x e y fanno riferimento alla stessa variabile, ovvero alla stessa locazione di memoria. Una variabile di riferimento come y non fa altro che applicare un altro nome a tale locazione di memoria. A questo punto, qualsiasi cosa facciamo a y come se la facessimo a x (e viceversa). Ad esempio:
int x; int& y=x; y=3; // assegno a y il valore 3 cout<<x; // controllo cosa succede a x

stampa sullo schermo il valore 3. I riferimenti sono veramente utili quando vengono utilizzati come parametri di una funzione1. In una funzione decido di usare i riferimenti, ovvero lo schema di passaggio per riferimento (detto anche passaggio per indirizzo), quando voglio che le variabili (all'interno di main) modifichino il loro valore dopo la chiamata della funzione. Infatti, ogni cosa che avviene ai riferimenti all'interno della funzione si traduce in una modifica delle variabili a cui fanno riferimento. Diverso il caso del passaggio per valore in cui alla funzione viene passato il valore della variabile ma non la variabile stessa, che mantiene pertanto il suo valore originario. Le funzioni che fanno ricorso allo schema di passaggio per riferimento sono di tipo void (prive cio della parola chiave return). Esempio:
#include <iostream> using namespace std; // dichiarazione della funzione raddoppia void raddoppia(int& a) { a=a*2; }

1 In C, la prima volta che si incontra il simbolo & nell'istruzione di lettura scanf, ricordate?

int main( ) { int x=1; raddoppia(x); // chiamata della funzione cout<<x; system(pause); return 0; }

Ottengo: 2 Infatti a un riferimento a x (lo capisco dalla chiamata della funzione) e poich la funzione raddoppia a, cos viene raddoppiato il valore di x. Osservo che viene perso il valore originale della variabile x. La funziona raddoppia pu essere utilizzata anche in modo ripetuto, cio pu essere chiamata pi volte ogni volta facendo riferimento ad una variabile diversa. Ad esempio:
#include <iostream> using namespace std; // dichiarazione della funzione raddoppia void raddoppia(int& a) { a=a*2; } int main( ) { int x=1; int y=2; raddoppia(x),raddoppia(y); cout<<x<<'\n'<<y; system(pause); return 0; }

// chiamata della funzione

Ottengo:
2 4

Alternativamente potevo modificare la funzione raddoppia e aggiungere un parametro:


#include <iostream> using namespace std; // dichiarazione della funzione raddoppia void raddoppia(int& a,int& b) { a=a*2; b=b*2; } int main( ) { int x=1; int y=2; raddoppia(x,y); // chiamata della funzione cout<<x<<'\n'<<y; system(pause); return 0; }

Se invece non mi interessa o non voglio che i valori delle variabili x e y vengano modificati, utilizzer lo schema di passaggio per valore anzich per riferimento:
#include <iostream> using namespace std; // dichiarazione della funzione raddoppia (passaggio per valore) int raddoppia(int a) { a=a*2; return(a); } int main( ) { int x=1;

int y=2; cout<<x<< <<y; cout<<raddoppia(x)<< system(pause); return 0; }

<<raddoppia(y)<<'\n';

In questo caso ottengo:


1 2 2 4

ovvero il valore originario delle variabili x e y non stato modificato dalla chiamata della funzione. Consideriamo ora un altro aspetto del passaggio per riferimento (e delle funzioni void): ovvero la possibilit di avere pi valori di ritorno. Consideriamo la seguente funzione che utilizza lo schema di passaggio per valore:
int somma(int a,int b){ return (a+b); }

ovvero:
int somma(int a,int b){ int s; s=a+b; return(s); }

e la corrispondente funzione void che utilizza lo schema di passaggio per riferimento:


void somma(int a,int b, int& s){ s=a+b; }

(come si vede la funzione ha ora un parametro in pi, che un riferimento). Vediamo ora le funzioni all'opera. Passaggio per valore:
#include <iostream> using namespace std; int somma(int a,int b){ return (a+b); } int main( ) { int x=1; int y=2; cout<<La somma vale <<somma(x,y); system(pause); return 0; }

Passaggio per riferimento:


#include <iostream> using namespace std; void somma(int a,int b, int& s){ s=a+b; } int main( ) { int x=1; int y=2;

int z;

/* questa variabile, come ogni altra variabile, va dichiarata, anche se non le stato assegnato nessun valore */ somma(x,y,z); // chiamata della funzione cout<<La somma vale <<z; system(pause); return 0; }

Se ora io volessi che la funzione non faccia solo la somma ma anche la differenza (o anche altre operazioni), non potrei pi farlo utilizzando il passaggio per valore, perch posso avere un solo valore di ritorno (dovrei dichiarare due funzioni, una che faccia la somma e una che faccia la differenza). Non ho invece questa limitazione con le funzioni void, che possono avere pi valori di ritorno. Vediamo subito un esempio:
#include <iostream> using namespace std; void somma_differenza(int a,int b, int& s, int& d){ s=a+b; d=a-b; } int main( ) { int x=1; int y=2; int z,w; somma_differenza(x,y,z,w); // chiamata della funzione cout<<La somma vale <<z; cout<<La differenza vale <<w; system(pause); return 0; }

(il numero di parametri di riferimento nella funzione corrisponde al numero dei valori di ritorno della funzione, in questo caso due). Esercizio1: Scrivi una funzione che, dati due interi, permetta di calcolare il doppio del primo pi il secondo e il doppio del secondo pi il primo. Successivamente, scrivi un programma di verifica per la funzione. Soluzione: Chiamo calcola la funzione richiesta:
void calcola(int a,int b, int& c,int& d){ c=2*a+b; d=2*b+a; }

Programma di verifica:
#include <iostream> using namespace std; void calcola(int a,int b, int& c,int& d){ c=2*a+b; d=2*b+a; } int main( ) { int x=1; int y=2; int z,w; calcola(x,y,z,w); cout<<z<<endl; cout<<w<<endl; system(pause); return 0; }

/* chiamata della funzione (c e d sono riferimenti a z e w rispettivamente */

Esercizio 2: Scrivi una funzione che realizzi la seguente trasformazione di coordinate: (x,y)(4*x+y,y-x). Successivamente, scrivi un programma di verifica per la funzione. Soluzione: Chiamo trasf la funzione richiesta:
void trasf(float& x,float& y){ float t=x; x=4*x+y; y=y-t; }

Programma di verifica:
#include <iostream> using namespace std; void trasf(float& x,float& y){ float t=x; x=4*x+y; y=y-t; } int main( ) { float a,b; cout<<Inserisci l'ascissa: ; cin>>a; cout<<Inserisci l'ordinata: ; cin>>b; trasf(a,b); /* chiamata della funzione (x un riferimento ad a, mentre y un riferimento a b) */ cout<<La nuova ascissa : <<a<<endl; cout<<La nuova ordinata : <<b<<endl; system(pause); return 0; }

ATTENZIONE! Sarebbe stato un errore definire la funzione nel seguente modo:


void trasf(float& x,float& y){ x=4*x+y; y=y-x; }

Esercizio 3: Scrivi una funzione void che scambia tra loro il valore di due variabili (sugg. la tecnica per definire la funzione la stessa dell'esercizio 2).