1 / 30

Funzioni e Procedure

Funzioni e Procedure. Marco D. Santambrogio – marco.santambrogio@polimi.it Ver. aggiornata al 18 Aprile 2012. Obiettivi. Funzioni Scope delle variabili. Introduzione. Spesso alcuni gruppi di operazioni vengono ripetute in diverse parti all ’ interno del medesimo programma

mrinal
Download Presentation

Funzioni e Procedure

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Funzioni e Procedure Marco D. Santambrogio – marco.santambrogio@polimi.it Ver. aggiornata al 18 Aprile 2012

  2. Obiettivi • Funzioni • Scope dellevariabili

  3. Introduzione • Spesso alcuni gruppi di operazioni vengono ripetute in diverse parti all’interno del medesimo programma • Si pensi ad esempio a un programma di gestione di matrici • È plausibile pensare che una matrice dovrà essere stampata a video in numerosi momenti • Il codice relativo alla stampa è sempre lo stesso (due cicli for annidati) • È quindi utile definire una sola volta questo gruppo di istruzioni e dare un nome ad esso • Ogni volta che si vuole stampare a video una matrice sarà sufficiente indicare il nome assegnato

  4. Sottoprogrammi • Un sottoprogramma è: • un insieme di istruzioni dotato di nome • descritto (definito) una sola volta • attivabile (richiamabile o invocabile) all’interno del programma o di un altro sottoprogramma • Alcuni sottoprogrammi sono già definiti • si pensi alla scanf e alla printf • dietro a questi nomi vi sono una serie di istruzioni in grado di, rispettivamente, intercettare la pressione dei tasti e di visualizzare un carattere sullo schermo • chi richiama queste funzioni non si preoccupa di come sono fatte, basta sapere solo cosa fanno (visione black box)

  5. Sottoprogrammi: motivazioni • Astrazione e leggibilità: • enucleano parti di codice, nascondendo dettagli algoritmici e di codifica • il nome di programma si presenta come “un’operazione elementare” • Strutturazione e scomposizione funzionale del programma: • consentono una stesura del programma che riflette un’analisi funzionale del problema • Collaudo: • verifica di correttezza della soluzione facilitata dal poter verificare la correttezza prima dei singoli sottoprogrammi e poi dell’intero programma visto come insieme di chiamate che si scambiano informazioni • Compattezza ed efficienza del codice: • si evita di ripetere sequenze di istruzioni in più parti del programma • Modificabilità: • una sola modifica vale per tutte le attivazioni del sottoprogramma • Riuso: • sottoprogrammi non troppo specifici possono essere raccolti in librerie utilizzabili da programmi diversi

  6. Funzioni e procedure • I sottoprogrammi si differenziano per la logica di definizione per l’uso e per la modalità di chiamata e possono essere • di tipo funzionale • di tipo procedurale • Sottoprogrammi di tipo funzionale (funzioni) possono essere considerati una astrazione di valore • l’invocazione della funzione associa al nome della funzione il valore del risultato calcolato dal sottoprogramma • Sottoprogrammi di tipo procedurale (procedure) possono essere considerati una astrazione di operazioni • l’invocazione della procedura è associata all’esecuzione delle istruzioni del sottoprogramma che realizzano l’operazione specificata dal sottoprogramma • Ad esempio: leggi(N); /* procedura*/ Fatt = fattoriale(N); /* funzione*/

  7. Funzioni e procedure in C • In C esistono solo le funzioni. • Le procedure sono particolari funzioni che non restituiscono nulla • Quindi parleremo solo di funzioni intendendo sia le funzioni che le procedure • Definire una funzione secondo il linguaggio C implica: • dichiarazione del prototipo della funzione (nella sezione dichiarativa) • definizione della funzione • invocazione o chiamata della funzione (nel codice che necessita della funzioni)

  8. Calcolare la somma dei fattoriali dei primi 100 numeri naturali: 0!+1!+2! … + 99!+100! #include <stdio.h> int fattoriale(int); main(){ int numero; /* numero di cui voglio calcolare il fattoriale */ int fatt; /* memorizzo il fattoriale di numero */ int somma; somma = 0; for(numero=0; numero<=100; numero++) { fatt = fattoriale(numero); somma = somma + fatt; } printf(“La somma dei fattoriali dei primi 100 naturali e’ %d”, somma);

  9. Dichiarazione del prototipo • Il prototipo definisce: • il nome della funzione • il tipo (funzione, procedura) • il tipo dei parametri in ingresso e in uscita • Chi utilizzerà la funzione dovrà rispettare la sintassi definita nel prototipo • Prototipo funzione <tipo_ris> <nome_funz> (<lista tipi dei parametri>); • Prototipo procedura (void è una parola chiave del C che indica assenza di tipo) void <nome_funz> (<lista tipi dei parametri>);

  10. Definizione del sottoprogramma • La definizione del sottoprogramma va messa dopo il main. Ha la stessa struttura del main (in realtà anche il main è una funzione): • Una parte dichiarativa • Una parte esecutiva <tipo> <nome> (tipo par_for1, tipo par_for2 ...) { parte dichiarativa locale parte esecutiva } • <tipo> <nome> (tipo par_for1, tipo par_for2 ...) è la testata della funzione • par_for1, par_for2 sono i nomi dei parametri formali della funzione, il cui tipo deve corrispondere in modo ordinato ai tipi elencati nella dichiarazione del prototipo

  11. Definizione della funzione fattoriale e i parametri formali int fattoriale(int n){ int risultato=1; int i; for (i = 1; i <= n; i++) risultato = risultato * i; return risultato; } • Parametri Formali: • Rappresentano un riferimento simbolico (identificatori) a oggetti utilizzati all’interno della funzione • Sono utilizzati dalla funzione come se fossero variabili dichiarate localmente • Il valore iniziale di parametri formali viene definito all’atto della chiamata della funzione tramite i parametri attuali (passaggio di parametri) Le funzioni in C sono funzioni in senso matematico, il tipo del valore di ritorno definisce il Codominio mentre i valori possibili dei parametri in ingresso corrispondono al Dominio

  12. Invocazione o chiamata • Nel corpo del main o di un’altra funzione indica il punto in cui va eseguita la parte del codice presente nella definizione di funzione • Invocazione di funzione • come operando in una espressione • <espressione> = <… nomefunzione(par_att1 …)…>; • Invocazione di procedura • come un’istruzione • nomeprocedura(par_att1, …); • In entrambi i casi: • par_att1,… sono i parametri attuali che devono corrispondere per ordine e per tipo ai parametri formali • I parametri attuali possono essere variabili, costanti o espressioni definite nell’ambiente chiamante, i cui valori all’atto della chiamata vengono copiati nei parametri formali

  13. Istruzione return • Parola chiave C utilizzata solo nelle funzioni • Sintassi return <espressione> • È l’ultima istruzione di una funzione e indica: • il punto in cui il controllo torna al chiamante • il valore restituito • In una funzione • deve esserci almeno un’istruzione di return • possono esserci più istruzioni di return ma in alternativa • la funzione può restituire un solo valore

  14. Chiamata di un sottoprogramma • All’atto della chiamata, il controllo dell’esecuzione passa dal chiamante al chiamato • Il codice del chiamato viene eseguito • Al termine dell’esecuzione il controllo ritorna al chiamante, all’istruzione successiva a quella della chiamata codice chiamante Inizio programma Istruzione 1 Istruzione 2 Chiama funzione Istruzione 3 Passaggio del controllo Ritorno del controllo funzione chiamata Istruzione 1 Istruzione 2 Istruzione 3 Istruzione 4 return

  15. Scambio di informazioni • Il chiamato deve poter ricevere dal chiamante i valori attuali sui quali eseguire le operazioni definite nel sottoprogramma • Il chiamato deve poter fornire al chiamante i risultati dell’elaborazione • Lo scambio di informazioni tra chiamante e chiamato può avvenire: • valore restituito da una funzione (dal chiamato al chiamante) • vale solo per le funzioni • per fornire un valore al chiamante • passaggio dei parametri (dal chiamante al chiamato) • per fornire i valori in ingresso al chiamato • per fornire i risultati di operazioni al chiamante • variabili globali (in entrambe le direzioni) • fortemente sconsigliato

  16. Passaggio dei parametri • Il passaggio dei parametri consiste nell’associare, all’atto delle chiamata di un sottoprogramma, ai parametri formali i parametri attuali • Se il prototipo di una funzione è float circonferenza (float raggio); • Invocare questa funzione significa eseguire l’istruzione c = circonferenza(5.0); • In questo modo la variabile raggio (il parametro formale) assumerà per quella particolare invocazione il valore 5 (il parametro attuale). • Lo scambio di informazioni con passaggio dei parametri tra chiamante e chiamato può avvenire in due modi: • Passaggio per valore • Passaggio per indirizzo

  17. Passaggio per VALORE • All’atto della chiamata il valore del parametro attuale viene copiato nelle celle di memoria del corrispondente parametro formale. • Il parametro formale e il parametro attuale si riferiscono a due diverse celle di memoria • Il sottoprogramma in esecuzione lavora nel suo ambiente e quindi sui parametri formali • I parametri attuali non vengono modificati

  18. Esempio: passaggio per valore float circonferenza(float raggio) { float circ; circ = raggio * 3.14; raggio = 7; /*istruzione senza senso, voglio solo vedere cosa succede modificando il valore di un paramentro formale*/ return circ; } /* nel main */ float c,r=5; c=circonferenza(r); /*Attenzione! r vale sempre 5 */ Ambiente della funzione circonferenza circ raggio Quando la funzione termina il valore di circ in circonferenza viene copiato in c nel main Quando invoco la funzione in raggio viene copiato il valore di r c r Ambiente della funzione main

  19. Scope delle variabili

  20. Introduzione • Con le funzioni è stato introdotto un meccanismo per definire dei piccoli programmi all’interno di altri programmi • Questi piccoli programmi sono autonomi con il resto del codice • Al loro interno sono definite le proprie variabili ed il canale di comunicazione con il codice chiamante (passaggio paramentri, return) • A supporto di questo meccanismo deve esistere una gestione degli identificatori delle variabili • È infatti possibile avere due variabili con lo stesso nome a patto che abbiano raggio di visibilità disgiunto

  21. Visibilità • Visibilità di un identificatore: • indicazione della parte del programma in cui tale identificatore può essere usato • Ambiente globale del programma • insieme di identificatori (tipi, costanti, variabili) definiti nella parte dichiarativa globale • regole di visibilità: visibili a tutte le funzioni del programma • Ambiente locale di una funzione • insieme di identificatori definiti nella parte dichiarativa locale e degli identificatori definiti nella testata (parametri formali) • Regole di visibilità: visibili alla funzione e ai blocchi in essa contenuti • Ambiente di blocco • insieme di identificatori definiti nella parte dichiarativa locale del blocco • regole di visibilità: visibili al blocco e ai blocchi in esso contenuti

  22. Esempi int x; f() { int y; y=1; } int x; g(int y, char z) { int k; int l; … } f(int x) { int x; } • La visibilità di y si estende dal punto di dichiarazione fino alla fine del blocco di appartenenza • y e z locali alla funzione g,con visibilità nel blocco racchiuso da parentesi graffe • k e l hanno la stessa visibilità • Errata! Si tenta di definire due volte la variabile locale x nello stesso blocco

  23. Mascheramento (shadowing) • Un nome ridefinito all’interno di un blocco nasconde il significato precedente di quel nome • Tale significato è ripristinato all’uscita del blocco più interno int x; /*nome globale*/ int f() { int x; /*x locale che nasconde x globale*/ x=1; /*assegna 1 al primo x locale*/ { int x; /* nasconde il primo x locale*/ x=2; /*assegna 2 al secondo x locale*/ } x=3; /*assegna 3 al primo x locale*/ } scanf (“%d”, &x); /*inserisce un dato in x globale*/ • In caso di omonimia di identificatori in ambienti diversi è visibile quello dell’ambiente più “vicino”

  24. Visibilità Livello globale g1,g2,g3 a,b main a,c blocco1 f1 a,d blocco2 d blocco3 char g1, g2, g3; main() { int a, b; … {/*blcco1*/ double a,c; } … } void f1(){ … {/*blocco2*/ char a,d; } … {/*blocco3*/ float d … } }

  25. Ambiente di esecuzione • L’ambiente di esecuzione di una funzione (variabili e parametri formali) viene creato al momento della chiamata e rilasciato quando la funzione termina • In una sequenza di chiamate, l’ultima chiamata è la prima a terminare • La zona di memoria di lavoro che contiene l’ambiente di esecuzione di un sottoprogramma è gestito con la logica di una pila (stack) • L’ultimo elemento inserito nello stack è il primo ad essere estratto • Logica LIFO (Last In First Out)

  26. Ambiente di esecuzione: esempio Ambiente c Ambiente b Ambiente a void a (); void b(); void c(); main(){ … a(); … } Esecuzione di a Esecuzione di b Esecuzione di c Termine di c Termine di b Termine di a void a (){ printf(“Esecuzione di a\n”); b(); printf(“Termine di a\n”); } void b(){ printf(“Esecuzione di b\n”); c(); printf(“Termine di b\n”); } void c(){ printf(“Esecuzione di c\n”); … printf(“Termine di c\n”); }

  27. Record di attivazione • Alla chiamata di una funzione • si alloca uno spazio di memoria (record di attivazione) in cima allo stack per contenere i parametri formali e le variabili locali • lo spazio viene rilasciato quando la funzione termina • Il record di attivazione contiene: • L’ambiente locale della funzione • L’indirizzo di ritorno al chiamante • Funzionamento: • Ad ogni attivazione viene allocato un record di attivazione • Al termine dell’attivazione il record viene rilasciato (l’area di memoria è riutilizzabile) • La dimensione del record di attivazione è già nota in fase di compilazione • Il numero di attivazioni della funzione non è noto • Il primo record di attivazione è destinato al main()

  28. Lo stack • Nello stack, i record vengono allocati “uno sopra l’altro”; il primo record dello stack è relativo all’ultima funzione attivata e non ancora terminata • Lo stack cresce dal basso verso l’alto • Stack pointer: registro della CPU che contiene l’indirizzo della cima della pila • Una parte della RAM è destinata a contenere lo stack • Stack overflow: quando l’area della RAM destinata allo stack viene superata (troppi annidamenti di chiamate) SP 312 312 311 Operazione di inserimento: -incremento SP -scrittura in parola indirizzata da SP Operazione di estrazione: -lettura da parola indirizzata da SP -decremento SP 310 ... 303

  29. Esempio ... etc. Act. RecordP2(2) Act. RecordP1(2) Act. RecordP2(1) Act. RecordP1(1) Act. RecordMain Variabili globali Main P1 P2 Chiama P1

  30. Fonti per lo studio + Credits • Fonti per lo studio • Credits • Gianluca Palermo

More Related