Concetto di funzione
Se nella realizzazione di un programma il codice diventa molto lungo o
in più parti vengono ripetute sequenze di istruzioni uguali, è conveniente
raggruppare segmenti di codice in moduli autonomi identificati da un nome.
Questi moduli, detti funzioni, possono essere eseguiti
in ogni punto del programma in cui sono richiesti scrivendo semplicemente
il loro nome.
L'organizzazione di un programma in funzioni comporta anche il vantaggio
di poterlo suddividere in parti che possono essere modificate in maniera
indipendente l’una dall’altra.
Definizione,dichiarazione e chiamata
Definizione:
tipo nome(tipo1 par1….,tipoN, parN){
Corpo..
}
Dichiarazione prototipo
tipo nome (tipo1 par1,…,tipoN parN);
par1,…,parN sono i parametri formali della funzione.
Chiamata
nome(esp1,…,espN);
esp1,…,espN sono dei valori(di
variabili,costanti o espressioni) e rappresentano gli argomenti attuali
della funzione.
Devono essere di tipo compatibile con quelli dei corrispondenti parametri
formali.
Istruzione return
Il corpo di una funzione puo contenere una o più istruzioni return.
Sintassi
return espressione;
l’istruzione return termina l’esecuzione della funzione e associa al suo nome il valore di espressione. Se la funzione non restituisce un valore(funzioni void) return espressione non è presente.
Definizione di funzione
/* Funzione che calcola il massimo comune divisore MCD tra due numeri interi positivi*/
int Mcd(int a,int b){
int resto;
while(b!=0){
resto=a%b;
a=b
b=resto;
}
return a
}
Prototipo di funzione
Le funzioni devono essere anteposte al blocco di istruzioni della funzione
main().
Se vogliamo collocare il codice delle funzioni dopo il blocco del main()
dobbiamo preventivamente dichiararle attraverso un loro prototipo,
costituito dal tipo, dal nome e dalla segnatura della funzione anteposto
al blocco main().
#include <iostream>
Using namespace std;
int Mcd(int a, int b);// prototipo
int main(){
int num1,num2;
cout<< "inserisci una coppia di numeri:";
cin>>num1>>num2;
cout <<"il M.C.D. tra"
<< num1<<" e " << num2
<< " vale:"
<< Mcd(num1,num2)// chiamata
<< endl;
}
Parametri e variabili locali
Un parametro formale è una variabile locale della funzione cui viene assegnato il valore del corrispondente argomento attuale al momento della chiamata. Le variabili locali di una funzione sono visibili solo nella funzione in cui sono dichiarate ed esistono soltanto durante la sua esecuzione. Al termine della funzione la memoria occupata delle variabili locali viene restituita al sistema.
Chiamata della funzione Mcd()
La chiamata di funzione Mcd (num1,num2) viene eseguita
nel modo seguente:
1 I valori degli argomenti attuali, num1
e num2, vengono assegnati, rispettivamente, ai parametri
formali a e b;
2 La funzione viene eseguita. I valori delle
variabili locali a e b (i
parametri formali) e della variabile resto sono modificati dalle istruzioni
contenute nel corpo della funzione. Le modifiche dei parametri formali non
si riflettono sui valori degli argomenti attuali, num1
e num2;
3 Il valore dell’ espressione che appare nell’istruzione
return (il valore di a) viene
associato al nome della funzione e ne rappresenta il valore di ritorno.
Funzioni void (procedure)
È possibile scrivere funzioni prive (void) di valore di ritorno.
Queste funzioni equivalgono a quelle che in altri linguaggi di programmazione
sono conosciute come procedure.
Diversamente, dalle altre funzioni, non possono essere impiegate in espressioni
ne possono contenere istruzioni return seguite da
valori.
Esempio:
void Stampa (int a, int b) {
cout<<a<<’\t’<<b<<endl;
}
Funzioni ricorsive
Una funzione può chiamare qualsiasi altra funzione, compresa se stessa.
In questi casi si parla di funzione ricorsiva.
Questa possibilità consente di semplificare la scrittura di programmi in
cui risulta naturale formulare il problema da risolvere in maniera ricorsiva.
Un esempio classico è il calcolo del fattoriale di un numero, definito come:
n!=n·(n-1)! con 0!=1 .
Esempio di funzione ricorsiva
//Calcolo del fattoriale di un numero
Unsigned long Fatt (unsigned long n) {
if (n<2) return 1;
return n * Fatt (n-1);
}
Funzioni di libreria
Una libreria è un file che contiene un insieme di funzione precompilate. Il C++ possiede una libreria standard, disponibile in tutte le implementazioni standard del linguaggio e contenente le medesime funzioni. Assieme al file di libreria deve essere fornito almeno uno di intestazione (header file) contenente le dichiarazioni delle funzioni impiegate, e indicare al linker il nome de file di libreria.
Alcune funzioni della libreria standard
Header file <cmath>
● fabs(x) valore
assoluto di x (reale);
● ceil (x) approssima
x a un intero per eccesso;
● floor(x) approssima
x a un intero per difetto;
● sqrt(x) radice
quadrata di x;
● pow(x,y) eleva
x alla potenza di y;
● exp(x) eleva
e alla potenza di x;
● log(x) logaritmo
naturale di x;
● log10(x) logaritmo
in base 10 di x;
● sin(x) e asin(x)
seno e arcoseno di x;
● cos(x) e acos
(x) coseno e arcoseno di x;
● tan(x) e atan(x)
tangente e arcotangente di x;
header file <cstdlib>
● abs(n) valore
assoluto di n (intero);
● rand() numero
pseudocasuale compreso tra 0 e la costante RAND_MAX
(solitamente 32767);
● srand(n) inizializza
il punto di partenza per la sequenza generata dalla funzione rand ();
● system(s)
interpreta la stringa s come un comando del sistema operativo.
Esempio:
int maxrand=10; //n sarà un numero casuale
compreso tra 0 e maxrand-1
n=rand()% maxrand;
Visibilità (scope) e durata (lifetime)
Visibilità:è la porzione di programma in cui un identificatore può essere referenziato per nome. Durata: è il periodo di tempo in cui un "oggetto" del programma occupa memoria. Può essere globale (se la durata coincide con quella di esecuzione del programma) o locale (quando la durata è limitata a quella di esecuzione di un blocco). Le funzioni hanno sempre durata globale.
Visibilità di una variabile
Visibilità a livello
di file : la variabile può essere impiegata in tutte le espressioni
del file sorgente dov'è dichiarata.
Visibilità locale : la variabile può essere
usata solo all'interno del blocco che contiene la sua dichiarazione.
In caso di blocco nidificati, la dichiarazione di una variabile omonima
"nasconde" quella dichiarata nel blocco superiore.
Esempio di visibilità
// visibilità a livello file
const double pi=3.14159;
int x; //variabile x globale
/* x,k e r hanno visibilità locale. All'interno di Funz()
la x globale è nascosta dalla x locale */
int Funz(double x, int k) {
double r;
r=pi*x/k;
. . .
}
Specificatore static
Lo specificatore static consente di modificare la visibilità o la durata di un "oggetto" del programma. Se è applicato a una variabile globale o a una funzione ne restringe la visibilià all'unità di traduzione in cui sono dichiarate. Se è applicato a variabili locali ne trasforma il periodo di vita in globale. Una variabile locale static viene inizializzata solo la prima volta che è eseguito il blocco in cui è dichiarata.
Esempio di variabile static
#include <iostream>
using namespace std;
usigned long Fibonacci();
int main() {
for(int i=0; i<5; i++)
cout<<Fibonacci()<<’\t’;
}
unsigned long Fibonacci() {
static unsigned long f1=0; //var. globale
static unsigned long f2=1;
unsigned long f;
f=f1+f2;
f1=f2;
f2=f;
return f;
}
L’uscita prodotta sarà:
1 2 3 5 8
Dichiarazione e definizione
In un programma variabili e funzioni possono essere dichiarati molte volte, ma la loro definizione deve essere una sola. Se compaiono più dichiarazioni di una stessa variabile o funzione, esse devono essere identiche. Ogni definizione è, implicitamente, anche una dichiarazione.
Lo specificatore extern
Lo specificatore extern consente di rendere visibili variabili globali definite in altre unità di traduzione. L'uso di extern per le funzioni è opzionale.
Esempio
Primo file
int x = 5; //definizione di x
//definizione di Quadrato
int Quadrato(int y){
return y * y;
}
Secondo file
#include<iostream>
using namespace std;
//dichiarazioni di x e Quadrato
extern int x; //rende visibile la x
int Quadrato(int);
int main(){
cout<<Quadrato(x)<<endl;
}
Il valore visualizzato sarà 25.
Programmazione modulare
Programmi di grosse dimensioni possono essere suddivisi in più file, ovvero è possibile creare una struttura modulare.
Esempio : programma su un solo file
double Sum(double x, double y) {return x + y;}
double Diff(double x, double y) {return x - y;}
int main(){
...
switch(operazione){
case 1: Sum(x, y); break;
case 2: Diff(x, y); break;
}
...
}
Scrivendo lo stesso programma su più file ogni file sarà compilato separatamente. Il linker ha il compito di associare le dichiarazioni di variabili e funzioni presenti in un file con le corrispondenti definizioni presenti negli altri file.
Lo stesso programma su più file
//file main.cpp
#include "funz.h"
main(){
...
switch(operatore){
case 1: Sum(x, y); break;
case 2: Diff(x, y); break;
}
...
}
//file funz.h
double Sum(double, double);
double Diff(double, double);
//file funz.cpp
double Sum(double x, double y) {return x + y;}
double Diff(double x, double y) {return x - y;}