FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float...

43
FUNZIONI ... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return 2 + x * sin(0.75); }

Transcript of FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float...

Page 1: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

FUNZIONI ...

Una funzione permette di dare un nome a una espressione rendendola parametrica

float f(){ return 2 + 3 * sin(0.75);

}

float f1(int x) {return 2 + x * sin(0.75);

}

Page 2: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

.. E PROCEDURE

Una procedura permette di dare un nome a una istruzione rendendola parametrica non denota un valore, quindi

non c’è tipo di ritorno void

void p(int x) {y = x * sin(0.75);

}

Page 3: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PROCEDURE come COMPONENTI SW

Una procedura è un componentesoftware che cattura l’idea di“macro-istruzione” molti possibili parametri, che

possono anche essere modificati nessun “valore di uscita” esplicito

Page 4: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PROCEDURE come SERVITORI

Come già una funzione,una procedura è un servitore• passivo• che serve un cliente per volta• che può trasformarsi in cliente

invocando se stessa

In C, una procedura ha la stessa strutturadi una funzione, salvo il tipo di ritorno cheè void

Page 5: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

RITORNO DA PROCEDURA

L’istruzione return provoca solo la restituzione del controllo al cliente

non è seguita da una espressione da restituire

quindi, non è necessaria se la proce-dura termina “spontaneamente” a fine blocco (cioè al raggiungimento della parentesi graffa di chiusura)

Page 6: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

COMUNICAZIONE CLIENTE/SERVITORE

Nel caso di una procedura, non esistendovalore di ritorno, cliente e servitore comu-nicano solo:• mediante i parametri• mediante aree dati globali

Il passaggio per valore non basta più: occorre il passaggio per riferimento per poter fare cambiamenti perma-

nenti ai dati del cliente.

Page 7: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO DEI PARAMETRI

In generale, un parametro può esseretrasferito: per valore o copia (by value)

si trasferisce il valore del parametro attuale

per riferimento (by reference) si trasferisce un riferimento al parametro

attuale

Page 8: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

ESEMPIO

Perché il passaggio per valore non basta?

Problema: scrivere una procedura che scambi i valori di due variabili intere.

A

T

B1

2

3

Specifica:Dette A e B le due variabili, ci si può appoggiare a una variabile ausiliaria T, e fare una “triangolazione” in tre fasi.

Page 9: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

ESEMPIO

Supponendo di utilizzare, senza preoccuparsi, il passaggio per valore usato finora, la codifica potrebbe essere espressa come segue:

A

T

B1

2

3

void scambia(int a, int b) { int t; t = a; a = b; b = t; return; /* può essere omessa */}

Page 10: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

ESEMPIO

Il cliente invocherebbe quindi la procedura così:

A

T

B1

2

3

main(){ int y = 5, x = 33; scambia(x, y); /* ora dovrebbe essere

x=5, y=33 ... MA NON E’ VERO !! */}

Perché non funziona??

Page 11: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

5

33

33

a

b

t

Page 12: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

ESEMPIO La procedura ha effettivamente scambiato i

valori di A e B al suo interno ma questa modifica non si è propagata al

cliente, perché sono state scambiate le co-pie locali alla procedura, non gli originali!

al termine della procedura, le sue variabili locali sono state distrutte nulla è rimasto del lavoro fatto dalla procedura!!

X 33

Y 5

A 5

B 33

Page 13: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER VALORE

cliente servitore

x 33copia

a33

valori (copiati) di x e y

Ogni azione fatta su a e b è strettamente locale al

servitore

y 5 b5

Page 14: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER VALORE

cliente servitore

x 33copia

a5

valori (copiati) di x e y

Quindi, a e b possono sìessere scambiati...

y 5 b33

… ma quando il servitoretermina, tutto scompare!

Page 15: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER VALORE

cliente

x 33

... e qui non è cambiato niente!!!

y 5

Page 16: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO DEI PARAMETRI IN C

Il C adotta sempre il passaggio per valore

è sicuro: le variabili del chiamante e del chiamato sono disaccoppiate

ma non consente di scrivere componenti software il cui scopo sia diverso dal calcolo di una espressione

per superare questo limite occorre il passaggio per riferimento (by reference)

Page 17: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER RIFERIMENTO

Il passaggio per riferimento (by reference)

non trasferisce una copia del valore del parametro attuale

ma un riferimento al parametro, in modo da dare al servitore accesso diretto al parametro in possesso del cliente

il servitore, quindi, accede direttamente al dato del cliente e può modificarlo.

Page 18: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO DEI PARAMETRI IN C

Il C non supporta direttamente il passaggioper riferimento è una grave mancanza lo fornisce indirettamente solo per alcuni

tipi di dati (array) quando serve occorre quindi costruirselo.

Il C++ e Java invece lo forniscono.

Page 19: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER RIFERIMENTO

Si trasferisce un riferimento ai parametriattuali (cioè i loro indirizzi)

cliente

x 33

y 5

Page 20: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER RIFERIMENTO

cliente servitore

riferimentoa

riferimenti a x e y(indirizzi)

x 33

y 5 b riferimento

Ogni azione fatta su a e b

in realtà è fatta su x e y nell’environment del cliente

Page 21: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER RIFERIMENTO

cliente servitore

riferimentoa

riferimenti a x e y(indirizzi)

x 33

y 5 b riferimento

Quindi, scambiando a e b...

Page 22: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER RIFERIMENTO

cliente servitore

riferimentoa

riferimenti a x e y(indirizzi)

x 5

y 3 b riferimento

… in realtà si scambiano x e y !

Page 23: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER RIFERIMENTO

cliente

x 5

... e alla fine la modifica permane!

y 33

Page 24: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PASSAGGIO PER RIFERIMENTO IN C++

In C++, il passaggio per riferimento si attiva cambiando leggermente la sintassi della dichiarazioni dei parametri nel servitore.

Non più:

<nomeTipo> <identificatore> ma bensì:

<nomeTipo> & <identificatore>

Il cliente, invece, non cambia.

Page 25: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

L’ESEMPIO RIFORMULATO

Quindi:

void scambia(int& a, int& b) { int t; t = a; a = b; b = t;}

main(){ int y = 5, x = 33; scambia(x, y); /* ora funziona! */}

Nota: un file sorgente C++ deve avere estensione .cpp

Page 26: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

ESEMPIO - RECORD DI ATTIVAZIONE

Caso del passaggio per valore:

RADL

33X

Y 5

A

B

33

5

5

33

T 33

RADL

Page 27: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

ESEMPIO - RECORD DI ATTIVAZIONE

Caso del passaggio per riferimento (C++):

RADL

X

Y

A

B

33

5

5

33

T 33

RADL

Page 28: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

REALIZZARE IL PASSAGGIO PER RIFERIMENTO IN C

Il C non fornisce direttamente un modo per attivare il passaggio per riferimento, come fa invece il C++

Però, il passaggio per riferimento è praticamente indispensabile

quindi, dobbiamo costruircelo.

È possibile costruirlo?

E se sì, come?

Page 29: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

REALIZZARE IL PASSAGGIO PER RIFERIMENTO IN C

Poiché passare un parametro per riferimento comporta la capacità di inserire nei record di attivazione indirizzi di variabili…

… gestire il passaggio per riferimento im-plica la capacità di accedere, direttamente o indirettamente, agli indirizzi delle varia-bili.

Page 30: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

REALIZZARE IL PASSAGGIO PER RIFERIMENTO IN C

In particolare occorre essere capaci di:

ricavare l’indirizzo di una variabile

dereferenziare un indirizzo di variabile, ossia “recuperare” la variabile dato il suo indirizzo.

Page 31: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

INDIRIZZO E DEREFERENCING

Il C offre a tale scopo due operatori, checonsentono di:

ricavare l’indirizzo di una variabile

operatore estrazione di indirizzo & dereferenziare un indirizzo di variabile

operatore di dereferenziamento *

Page 32: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

INDIRIZZO E DEREFERENCING

• Se x è una variabile,&x denota l’l-value:

• Se è l’indirizzo di una variabile,* denota l’r-value:

Page 33: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PUNTATORI

• Un puntatore è il costrutto linguistico introdotto dal C (e da molti altri linguaggi) come forma di accesso alla macchina sottostante.

• Un “tipo puntatore a T” è un tipo che denota l’indirizzo di memoria di una variabile di tipo T.

• Un PUNTATORE a T è una variabile di “tipo puntatore a T” che può contenere l’indirizzo di una variabile di tipo T.

Page 34: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

PUNTATORI

• Definizione di una variabile puntatore:

<tipo> * <nomevariabile> ;• Esempi:

int *p ;int* p ;int * p ;

Queste tre forme sono equivalenti, e definiscono p come “puntatore a intero”

Page 35: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

RICOSTRUIRE IL PASSAGGIO PER RIFERIMENTO IN C

• In C++ il cliente non deve fare esplicita-mente nulla: è il servitore che specifica che i parametri devono passare per riferimento.

• Volendo ricostruire tutto ciò in C:– il cliente deve passare esplicitamente gli

indirizzi

– il servitore deve prevedere esplicitamente dei puntatori come parametri formali

Page 36: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

IL SOLITO ESEMPIO

void scambia(int* a, int* b) { int t; t = *a; *a = *b; *b = t;}

main(){ int y = 5, x = 33;

scambia(&x, &y);}

Il cliente deve ricavare esplicitamentegli indirizzi di x e y, per passarli.

Page 37: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

a

b

t

5

33

x

y

33

Page 38: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

IL SOLITO ESEMPIO

void scambia(int* a, int* b) { int t; t = *a; *a = *b; *b = t;}

main(){ int y = 5, x = 33;

scambia(&x, &y);}

Il servitore deve prevedere esplicitamente dei puntatori

Cambia, da entrambi i lati, il contratto di comunicazione.

Page 39: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

OSSERVAZIONE

• Quando un puntatore è usato per realiz-zare il passaggio per riferimento, la funzione non dovrebbe mai alterare il valore del puntatore.

• Quindi, se a e b sono due puntatori:

*a = *b SI

a = b NO

Page 40: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

OSSERVAZIONE

• Quando un puntatore è usato per realiz-zare il passaggio per riferimento, la funzione non dovrebbe mai alterare il valore del puntatore.

NOTA:questo non significa che in generale una fun-

zione non debba o possa modificare un puntatore:semplicemente, non è opportuno che lo faccia se

esso realizza un passaggio per riferimento

Page 41: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

IL SOLITO ESEMPIO

void scambia(int* a, int* b) { int t; t = *a; *a = *b; *b = t;}

main(){ int y [] ={ 2,3 }; scambia( y[0], y[1] );}

Il cliente deve ricavare esplicitamentegli indirizzi di x e y, per passarli.

Page 42: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.

IL SOLITO ESEMPIO

void scambia( int y[], int n) { int t; t = y[n]; y[n]=y[n-1]; y[n-1]= t;}

main(){ int y[] ={ 2,3 }; scambia( y, 1 );}

Il cliente deve ricavare esplicitamentegli indirizzi di x e y, per passarli.

Page 43: FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return 2 + 3 * sin(0.75); } float f1(int x) { return.