Lezione 10 (21 marzo 2012)3

52
Funzioni in C

Transcript of Lezione 10 (21 marzo 2012)3

Page 1: Lezione 10 (21 marzo 2012)3

Funzioni in C

Page 2: Lezione 10 (21 marzo 2012)3

Servitore:• Un qualunque ente computazionale capace di nascondere la propria organizzazione interna

• presentando ai clienti una precisa interfaccia per lo scambio di informazioni

Cliente:• qualunque ente in grado di invocare uno o più servitori per

svolgere il proprio compito

Modello cliente/servitore

Page 3: Lezione 10 (21 marzo 2012)3

Modello cliente/servitoreUn servitore può• essere passivo o attivo

• servire molti clienti oppure costituire la risorsa privata diuno specifico cliente– in particolare: può servire un cliente alla volta, in

sequenza, oppure più clienti per volta, in parallelo

• trasformarsi a sua volta in cliente, invocando altriservitori o anche se stesso.

Page 4: Lezione 10 (21 marzo 2012)3

•Lo scambio di informazioni tra un cliente e un servitore può avvenire

in modo esplicito tramite le interfacce stabilite dal servitore

in modo implicito tramite aree-dati accessibili ad entrambi,

ossia l’ambiente condiviso

Comunicazione cliente/servitore

Page 5: Lezione 10 (21 marzo 2012)3

• Una funzione è un servitore– passivo– che serve un cliente per volta– che può trasformarsi in cliente invocando altre funzioni o se

stessa• Una funzione è un servitore dotato di nome che incapsula le

istruzioni che realizzano un certo servizio.• Il cliente chiede al servitore di svolgere il servizio

– chiamando tale servitore (per nome)– fornendogli le necessarie informazioni

• Nel caso di una funzione, cliente e servitore comunicanomediante l’interfaccia della funzione.

FUNZIONI COME SERVITORI

Page 6: Lezione 10 (21 marzo 2012)3

•L’interfaccia (o prototipo) di una funzione comprende

nome della funzionelista dei parametritipo del valore da essa denotato

• Esplicita il contratto di servizio fra cliente e servitore

•Cliente e servitore comunicano quindi mediantei parametri trasmessi dal cliente al servitore all’atto della chiamatail valore restituito dal servitore al cliente

Interfaccia di una funzione

Page 7: Lezione 10 (21 marzo 2012)3

• Calcolo del massimo di due valori

• Sequenza operazioni:– Il cliente comunica al

servitore i due valori– Il servitore calcola il massimo– Il servitore comunica al

cliente il valore del massimo

•Cliente e servitore devono essere d’accordo su:–il tipo dei valori int–quanti sono i valori 2–qual’è il nome del servitore max–qual’è il tipo del valore di ritorno int

•Il cliente non è interessato all’algoritmo che il servitore utilizza

5

3,5

ESEMPIO

Page 8: Lezione 10 (21 marzo 2012)3

ESEMPIO

• Quindi, dal lato del servitore dovrà esserci scritto:

– come si chiama– di quanti dati ha bisogno e di

che tipo– di che tipo è il valore calcolato

• Il cliente dovrà mandare alservitore identificato da quelnome– i dati di ingresso, in numero

e tipo giusti– ricevere il risultato

Page 9: Lezione 10 (21 marzo 2012)3

int max (int x, int y ){ /*interfacciaif (x>y) return x ;else return y;}

• Il simbolo max denota il nome della funzione

• Le variabili intere x e y sono i parametri della funzione

• Il valore restituito è un intero int

Funzioni: esempio C

Page 10: Lezione 10 (21 marzo 2012)3

• Il cliente passa informazioni al servitore mediante una serie di parametri

Parametri formali:sono specificati nella dichiarazione del servitoreesplicitano il contratto fra servitore e clienteindicano che cosa il servitore si aspetta dal cliente

Parametri attuali:sono trasmessi dal cliente all’atto della chiamatadevono corrispondere ai parametri formali in numero, posizione e tipo

Comunicazione cliente/servitore

Page 11: Lezione 10 (21 marzo 2012)3

Funzioni: esempio parametri

Page 12: Lezione 10 (21 marzo 2012)3

Legame tra parametri attuali e parametri formali:• effettuato al momento della chiamata, in modo

dinamico

Tale legame:vale solo per l’invocazione correntevale solo per la durata della funzione

Comunicazione cliente/servitore

Page 13: Lezione 10 (21 marzo 2012)3

Esempio

All’atto di questa chiamata della funzione, si effettua un legame tra:x e zy e 4

Page 14: Lezione 10 (21 marzo 2012)3

Esempio:

All’atto della chiamata della funzione si effettua il legame tra:x e 5y e z

Page 15: Lezione 10 (21 marzo 2012)3

Information hiding• La struttura interna (corpo) di una funzione è

completamente inaccessibile dall’esterno

• Così facendo si garantisce protezione dell’informazione(information hiding)

• Una funzione è accessibile solo attraverso la suainterfaccia

• Quindi posso cambiare l’algoritmo della funzione senza preoccuparmi di quello che succede dal lato del cliente

Page 16: Lezione 10 (21 marzo 2012)3

Definizione di funzione in C

<tipoValore> <nome>(<parametri-formali>) {

<corpo>}

<parametri-formali>o una lista vuota: voido una lista di variabili (separate da virgole)

visibili solo entro il corpo della funzione

<tipoValore>deve coincidere con il tipo del valore restituito dalla funzionePuò non esservi valore restituiti, in tal caso il tipo è void

La forma base è:return <espressione>;

Page 17: Lezione 10 (21 marzo 2012)3

Definizione di funzione in C

<tipoValore> <nome>(<parametri-formali>) {

<corpo>}

La forma base è:return <espressione>;

• Nella parte corpo possono essere presenti: definizioni e/o dichiarazioni locali (parte dichiarazioni) e un insieme di istruzioni (parte istruzioni)

• I dati riferiti nel corpo possono essere costanti, variabili, oppure parametri formali

• All'interno del corpo, i parametri formali vengono trattati come variabili

Page 18: Lezione 10 (21 marzo 2012)3

Funzioni: nascita e morte

• All’atto della chiamata:l’esecuzione del cliente viene sospesa e ilcontrollo passa al servitore

• Il servitore “vive” solo per il tempo necessario a svolgere il servizio

• Al termine, il servitore “muore”, e l’esecuzione torna al cliente

Page 19: Lezione 10 (21 marzo 2012)3

Chiamata di funzione

• La chiamata di funzione è un’espressione della forma

<nomefunzione> ( <parametri-attuali> )

• dove:

<parametri-attuali> ::=[ <espressione> ] { , <espressione> }

Page 20: Lezione 10 (21 marzo 2012)3

Funzioni: esempioFunzioni: esempio

int max (int x, int y ){if (x>y) return x ;

else return y;}

SERVITORE

Definizione della funzione

CLIENTE

Chiamata della funzione

main() {int z = 8;int m;m = max ( z, 4);

}

Parametri formali

Parametri attuali

Page 21: Lezione 10 (21 marzo 2012)3

Risultato di una funzione

• L’istruzione return provoca la restituzione del controllo al cliente, unitamente al valore della espressione che la segue.

• Eventuali istruzioni successive alla return non saranno mai eseguite

int max (int x, int y ){if (x>y) return x ;else return y;

}

Page 22: Lezione 10 (21 marzo 2012)3

Funzioni: esempioFunzioni: esempio

int max (int x, int y ){if (x>y) return x ;

else return y;}

SERVITORE

Definizione della funzione

CLIENTE

Chiamata della funzione

main() {int z = 8;int m;m = max ( z, 4);

}

Parametri formali

Risultato

Page 23: Lezione 10 (21 marzo 2012)3

Riassumendo

All’atto dell’invocazione di una funzione:

• si crea una nuova attivazione (istanza) del servitore

• si alloca la memoria per i parametri (e le eventuali variabili locali)

• si trasferiscono i parametri al servitore

• si trasferisce il controllo al servitore

• si esegue il codice della funzione

Page 24: Lezione 10 (21 marzo 2012)3

Passaggio dei parametri

In generale, un parametro può essere trasferito dal cliente al servitore:

• 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 25: Lezione 10 (21 marzo 2012)3

Passaggio per valore

• Si trasferisce una copia del valore del parametro attuale

cliente

Page 26: Lezione 10 (21 marzo 2012)3

Passaggio per valore

• Si trasferisce una copia del valore del parametro attuale

cliente servitore

Istanza del servitore

Ogni azionefatta su w èlocale al servitore

Valore (copiato) di z

copia

Page 27: Lezione 10 (21 marzo 2012)3

Passaggio per riferimento

• Si trasferisce un riferimento al parametro attuale

cliente

Page 28: Lezione 10 (21 marzo 2012)3

Passaggio per valore

• Si trasferisce un riferimento al parametro attuale

cliente servitore

Istanza del servitore

Ogni azionefatta su w èIn realtàfatta sulla variabile z del cliente

Riferimento a z(indirizzo)

riferimento

xx

Page 29: Lezione 10 (21 marzo 2012)3

Passaggio dei parametri in C

• In C, i parametri sono trasferiti sempre e solo per valore

si trasferisce una copia del parametro attuale, non l’originale

tale copia è strettamente privata e locale a quel servitore

il servitore potrebbe quindi alterare il valore ricevuto, senza che ciò abbia alcun impatto sul cliente

Page 30: Lezione 10 (21 marzo 2012)3

Passaggio dei parametri in C

• In C, i parametri sono trasferiti sempre e solo per valore

Conseguenza:

• è impossibile usare un parametro per trasferire informazioni verso il cliente

• per trasferire un’informazione al cliente si sfrutta il valore di ritorno della funzione

Page 31: Lezione 10 (21 marzo 2012)3

Perché il passaggio per valore non basta?

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

Specifica: Dette A e B le due variabili, ci si può appoggiare a una variabile ausiliaria T, e svolgere lo scambio in tre fasi

Frammento di codice:int a,b,t;...t = a; a = b; b = t;…

Esempio

Page 32: Lezione 10 (21 marzo 2012)3

Esempio

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

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

}

Page 33: Lezione 10 (21 marzo 2012)3

EsempioIl cliente invocherebbe quindi la procedura così:

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

x=5, y=33 ...MA NON È VERO

*/}

Perché non funziona?

Page 34: Lezione 10 (21 marzo 2012)3

Esempio: cosa è successo?

• 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 copie locali alla procedura, non gli originali

• al termine della procedura, le sue variabili locali sono state distrutte, quindi nulla è rimasto del lavoro svolto dalla procedura

Page 35: Lezione 10 (21 marzo 2012)3

Esempio: cosa è successo?• Ogni azione fatta su a e b è strettamente locale al servitore.

Quindi a e b vengono scambiati, ma quando il servitore termina, tutto scompare

cliente servitore

Valori (copiati) di a e b

copia

x

y

Page 36: Lezione 10 (21 marzo 2012)3

Passaggio dei parametri in C

Il C adotta sempre il passaggio per valore!

È sicuro: le variabili del cliente e del servitore sono disaccoppiate

... ma non consente di scrivere componenti software il cui scoposia diverso dal calcolo di una espressione

Per superare questo limite occorre il passaggio per riferimento

Page 37: Lezione 10 (21 marzo 2012)3

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

Passaggio per riferimento

Page 38: Lezione 10 (21 marzo 2012)3

Passaggio per riferimento

cliente

x

y

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

Page 39: Lezione 10 (21 marzo 2012)3

cliente servitore

Riferimenti a x e y (indirizzi)

riferimento

x

yriferimentoβ

α

Passaggio per riferimentoOgni azione fatta su a e b, in realtàè fatta su x e y nell’environment del

cliente

Page 40: Lezione 10 (21 marzo 2012)3

cliente servitore

Riferimenti a x e y (indirizzi)

riferimento

x

yriferimentoβ

α

Passaggio per riferimento

quindi, scambiando α e β, in realtà si scambiano x e y

Page 41: Lezione 10 (21 marzo 2012)3

Realizzare il passaggio per riferimento in C

• Il C non fornisce direttamente un modo per attivare il passaggio per riferimento -> a volte occorre costruirselo

• è una grave mancanza!

• il C lo fornisce indirettamente solo per alcuni tipi di dati

• quindi, occorre costruirselo quando serve.(vedremo più avanti dei casi)

Page 42: Lezione 10 (21 marzo 2012)3

Funzioni e strutture

• Con le funzioni si possono usare come parametri e come valore di ritorno le strutture (con gli array è un po’ diverso, come vedremo)

• L’utilizzo delle funzioni permette di costruire semplicemente applicazioni con la metodologia top-down

• Si scriva un programma che permette di– leggere due frazioni– calcolarne la somma– visualizzare il risultato

Page 43: Lezione 10 (21 marzo 2012)3

Esempio• Per prima cosa, definiamo le strutture dati:

– una frazione è costituita da un numeratore ed un denominatore

typedef struct { int num; int den; } frazione;

• Poi scriviamo l’algoritmo partendo dalla versione più astratta.Scriviamo il main invocando le varie funzioni che ci servono

main(){ frazione f1, f2, somma;

f1 = leggiFrazione();f2 = leggiFrazione();somma = sum(f1,f2);printf("%d/%d",somma.num,somma.den);

}

Page 44: Lezione 10 (21 marzo 2012)3

Esempio

• Poi implementiamo le funzioni che abbiamo invocato nel main:

frazione leggiFrazione(){ frazione f;

scanf("%d",&f.num);scanf("%d",&f.den);return f;

}

Page 45: Lezione 10 (21 marzo 2012)3

Esempio

• La somma di due frazioni si calcola così:– calcolo il minimo comun denominatore (minimo comune multiplo

dei denominatori); questo è il denominatore della somma– porto la prima frazione al comun denominatore– porto la seconda frazione al comun denominatore– calcolo la somma dei numeratori: questo è il numeratore della somma

frazione sum(frazione f1, frazione f2){ int mcd; // minimo comun denominatorefrazione somma;mcd = mcm(f1.den,f2.den);somma.den = mcd;f1 = portaDen(f1,mcd);f2 = portaDen(f2,mcd);somma.num = f1.num + f2.num;return somma;}

Page 46: Lezione 10 (21 marzo 2012)3

Esempio

• Infine implementiamo le funzioni che abbiamo usato nelle funzioni

• Per portare una frazione ad un denominatore, devo moltiplicarenumeratore e denominatore per la stessa quantità

nuovoNum/nuovoDen = vecchioNum/vecchioDen

• quindinuovoNum=vecchioNum*nuovoDen/vecchioDen

frazione portaDen(frazione f, int nDen){ frazione nuovo;

nuovo.den = nDen;nuovo.num = f.num*nDen/f.den;return nuovo;

}

Page 47: Lezione 10 (21 marzo 2012)3

Esempio

• Per calcolare il minimo comune multiplo di dueinteri, posso farne il prodotto e dividere per il massimo comun divisore dei due

int mcm(int a, int b){ return a*b/MCD(a,b);}

Page 48: Lezione 10 (21 marzo 2012)3

Esempio

• Per calcolare il MCD di due numeri, posso usare il metodo di Euclide

int MCD(int m, int n){ while (m != n)

if (m>n)m=m-n;

else n=n-m;return m;

}

Page 49: Lezione 10 (21 marzo 2012)3

#include <stdio.h>typedef struct { int num; int den; }

frazione;int MCD(int m, int n){ while (m != n)

if (m>n)m=m-n;

else n=n-m;return m;

}int mcm(int a, int b){ return a*b/MCD(a,b);}frazione portaDen(frazione f, int

nDen){ frazione nuovo;nuovo.den = nDen;nuovo.num = f.num*nDen/f.den;return nuovo;

}

frazione sum(frazione f1, frazione f2){ int mcd;

frazione somma;mcd = mcm(f1.den,f2.den);somma.den = mcd;f1 = portaDen(f1,mcd);f2 = portaDen(f2,mcd);somma.num = f1.num + f2.num;return somma;

}frazione leggiFrazione(){ frazione f;

scanf("%d",&f.num);scanf("%d",&f.den);return f;

}main(){ frazione f1, f2, somma;

f1 = leggiFrazione();f2 = leggiFrazione();somma = sum(f1,f2);printf("%d/%d",somma.num,somma.den);

}

Il programma risultante

Page 50: Lezione 10 (21 marzo 2012)3

Il programma risultante• E` abbastanza facile da scrivere e da capire• E` facile da modificare• Es: voglio assicurarmi che l’utente non inserisca una frazione che ha perdenominatore zero

• Intervengo in una sola funzione: la leggiFrazione– è una funzione di 4 istruzioni, quindi facile da capire e da

modificare

frazione leggiFrazione(){ frazione f;

do{ scanf("%d",&f.num);

scanf("%d",&f.den);if (f.den==0)

printf(“Re-inserire la frazione\n");} while (f.den == 0);

return f;}

Page 51: Lezione 10 (21 marzo 2012)3

Modificabilità

• Ora voglio che mi fornisca solo frazioni ai minimi termini

• Aggiungo una funzione riduci. Posso invocarla nel main

main(){ frazione f1, f2, somma;

f1 = leggiFrazione();f2 = leggiFrazione();somma = riduci(sum(f1,f2));printf("%d/%d",somma.num,somma.den);

}

Page 52: Lezione 10 (21 marzo 2012)3

Modificabilità

• Poi definisco la nuova funzione riduci

• Per ridurre una funzione ai minimi termini, basta dividere numeratore e denominatore per il loro MCD

frazione riduci(frazione f){ int m = MCD(f.num,f.den);

f.num = f.num/m;f.den = f.den/m;return f;

}