DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
Funzioni e Procedure
Marco D. Santambrogio – [email protected]
Ver. aggiornata al 18 Aprile 2012
Obiettivi
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• Funzioni
• Scope delle variabili
2
Introduzione
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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
3
Sottoprogrammi
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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)
4
Sottoprogrammi: motivazioni
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
•
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
5
Funzioni e procedure
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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

l’invocazione della funzione associa al nome della funzione il valore del risultato
calcolato dal sottoprogramma
• Sottoprogrammi di tipo funzionale (funzioni) possono
essere considerati una astrazione di valore
• 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*/
6
Funzioni e procedure in C
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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)
7
Calcolare la somma dei fattoriali dei primi 100 numeri
naturali: 0!+1!+2! … + 99!+100!
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
#include <stdio.h>
int fattoriale(int);
main(){
int numero;
int fatt;
int somma;
somma = 0;
/* numero di cui voglio calcolare il fattoriale */
/* memorizzo il fattoriale di numero */
for(numero=0; numero<=100; numero++)
{
fatt = fattoriale(numero);
somma = somma + fatt;
}
printf(“La somma dei fattoriali dei primi 100 naturali e’ %d”, somma);
8
Dichiarazione del prototipo
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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>);
9
Definizione del sottoprogramma
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
•
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
10
Definizione della funzione
fattoriale e i parametri formali
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
int fattoriale(int n){
int risultato=1;
int i;
for (i = 1; i <= n; i++)
risultato = risultato * i;
return risultato;
}
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
• 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)
11
Invocazione o chiamata
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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
12
Istruzione return
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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
13
Chiamata di un sottoprogramma
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
•
•
•
All’atto della chiamata, il
controllo dell’esecuzione
passa dal chiamante al
chiamato
Il codice del chiamato
viene eseguito
codice chiamante
Inizio
programma
Istruzione 1
Istruzione 2
Chiama funzione
Istruzione 3
Passaggio
del controllo
Al termine
dell’esecuzione il
controllo ritorna al
chiamante, all’istruzione
successiva a quella della
chiamata
funzione chiamata
Ritorno
del
controllo
Istruzione 1
Istruzione 2
Istruzione 3
Istruzione 4
return
14
Scambio di informazioni
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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
•
•
per fornire i valori in ingresso al chiamato
per fornire i risultati di operazioni al chiamante
•
fortemente sconsigliato
passaggio dei parametri (dal chiamante al chiamato)
variabili globali (in entrambe le direzioni)
15
Passaggio dei parametri
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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
16
Passaggio per VALORE
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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
17
Esempio: passaggio per valore
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
float circonferenza(float raggio)
{
Ambiente della funzione
float circ;
circonferenza
circ = raggio * 3.14;
raggio = 7; /*istruzione senza
circ
raggio
senso, voglio solo vedere
cosa succede modificando il
valore di un paramentro
Quando la funzione
formale*/
termina il valore di circ in
return circ;
circonferenza viene
Quando invoco la funzione
copiato in c nel main
in raggio viene
}
copiato il valore di r
/* nel main */
float c,r=5;
r
c=circonferenza(r);
/*Attenzione! r vale sempre 5 */
c
Ambiente della funzione
main
18
Scope delle variabili
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
19
Introduzione
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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
20
Visibilità
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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
21
Esempi
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
int x;
f()
{
int y;
y=1;
}
• La visibilità di y si estende dal punto di
dichiarazione fino alla fine del blocco di
appartenenza
int x;
g(int y, char z)
{
int k;
int l;
…
}
• y e z locali alla funzione g,con visibilità nel blocco
racchiuso da parentesi graffe
f(int x)
{
int x;
}
• k e l hanno la stessa visibilità
• Errata! Si tenta di definire due volte la variabile
locale x nello stesso blocco
22
Mascheramento (shadowing)
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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;
int f() {
int x;
x=1;
{
int x;
x=2;
}
x=3;
}
scanf (“%d”, &x);
/*nome globale*/
/*x locale che nasconde x globale*/
/*assegna 1 al primo x locale*/
/* nasconde il primo x locale*/
/*assegna 2 al secondo x locale*/
/*assegna 3 al primo x locale*/
/*inserisce un dato in x globale*/
• In caso di omonimia di identificatori in ambienti
diversi è visibile quello dell’ambiente più “vicino”
23
Visibilità
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
char g1, g2, g3;
main()
{
int a, b;
…
{/*blcco1*/
double a,c;
}
…
}
void f1(){
…
{/*blocco2*/
char a,d;
}
…
{/*blocco3*/
float d
…
}
}
g1,g2,g3
a,b
Livello globale
main
a,c
blocco1
f1
a,d
blocco2
d
blocco3
Ambiente di esecuzione
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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)
25
Ambiente di esecuzione: esempio
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
void a ();
void b();
void c();
main(){
…
a();
…
}
void a (){
printf(“Esecuzione
b();
printf(“Termine di
}
void b(){
printf(“Esecuzione
c();
printf(“Termine di
}
void c(){
printf(“Esecuzione
…
printf(“Termine di
}
Esecuzione
Esecuzione
Esecuzione
Termine di
Termine di
Termine di
di a
di b
di c
c
b
a
di a\n”);
a\n”);
di b\n”);
b\n”);
Ambiente c
Ambiente b
di c\n”);
Ambiente a
c\n”);
26
Record di attivazione
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• 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()
27
Lo stack
•
•
•
•
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
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
Operazione di inserimento:
-incremento SP
-scrittura in parola indirizzata da SP
Operazione di estrazione:
-lettura da parola indirizzata da SP
-decremento SP
312
311
310
...
303
28
Esempio
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
Main
...
P1
etc.
P2
Chiama P1
Act. Record P2(2)
Act. Record P1(2)
Act. Record P2(1)
Act. Record P1(1)
Act. Record Main
Variabili globali
29
Fonti per lo studio + Credits
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE
• Fonti per lo studio
• Credits
 Gianluca Palermo
Scarica

PPT