Funzioni in C++
Concetti avanzati
Moreno Marzolla
moreno.marzolla@pd.infn.it
Moreno Marzolla Fondamenti di Informatica 2
Copyright © 2006 Moreno Marzolla
This work is licensed under the Creative Commons Attribution- Noncommercial-Share Alike 2.5 Italy License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc- sa/2.5/it/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
Passaggio di vettori Passaggio di vettori
Abbiamo visto come passare gli eventuali parametri ad una funzione
Come si fa a passare un vettore (array) come parametro di una funzione?
int somma( int a, int b ) {
int risultato;
risultato = a+b;
return risultato;
}
Sintassi Sintassi
Es: Scrivere una funzione somma_vet() che riceve come parametro un array a[] di 10 interi. La funzione restituisce come risultato intero, che è la somma dei valori di tutti gli elementi del vettore a[]
int somma_vet( int a[] ) {
int i;
int s = 0;
for ( i=0; i<10; i++ ) { s = s+a[i];
}
return s;
}
Nota: non si deve mai
specificare la dimensione
(numero di elementi) di a!
Moreno Marzolla Fondamenti di Informatica 5
Osservazione Osservazione
Quando si scrive una funzione che richiede un parametro di tipo array, si mettono parentesi []
dopo il nome del parametro
Spesso è anche necessario passare la
dimensione dell'array alla funzione, perché la funzione non ha altro modo per richiederne la dimensione.
Nell'esempio precedente assumevamo che l'array passato come parametro avesse SEMPRE 10 elementi
Moreno Marzolla Fondamenti di Informatica 6
Esempio Esempio
#include <iostream>
using namespace std;
int somma_vet( int a[], int dim_a ) {
int i;
int s = 0;
for ( i=0; i<dim_a; i++ ) { s = s+a[i];
}
return s;
}
int main( void ) {
int vet[5] = {1, 2, 3, 4, 5};
cout << La somma vale << somma_vet( vet, 5 ) << endl;
return 0;
}
Questo parametro viene usato per indicare la dimensione (numero di elementi) del vettore a[]
Moreno Marzolla Fondamenti di Informatica 7
Nota Nota
Attenzione che, a differenza di tutti gli altri parametri, i parametri di tipo array vengono modificati se si tenta di scriverci dentro
Esempio
#include <iostream>
using namespace std;
void azzera( int a[], int dim_a ) {
int i;
for ( i=0; i<dim_a; i++ ) { a[i] = 0;
} }
int main( void ) {
int vet[5] = {1,2,3,4,5};
azzera( vet, 5 );
// a questo punto tutti gli elementi di vet[] valgono zero return 0;
}
Moreno Marzolla Fondamenti di Informatica 8
Esercizi Esercizi
Scrivere una funzione prodotto_scalare() con le seguenti caratteristiche:
La funzione accetta tre parametri: un vettore di double a[], un vettore di double b[] (che devono avere la stessa dimensione), e la loro dimensione dim
La funzione restituisce un numero ottenuto facendo il prodotto scalare tra i vettori a[] e b[], ossia il valore calcolato come:
a[0]*b[0] + a[1]*b[1] + ... + a[n-1]*b[n-1]
assumendo che n sia la dimensione di a[] e b[]
Moreno Marzolla Fondamenti di Informatica 9
Passaggio per valore Passaggio per valore
Il modo di passare parametri che abbiamo usato fino ad ora (con l'esclusione dei vettori) si chiama passaggio di parametri per valore
Significa che ad una funzione viene passato una copia del valore del parametro
Se all'interno della funzione modifico il valore di un parametro, la modifica non avrà alcun effetto al di fuori della funzione
#include <iostream>
using namespace std;
void azzera( int a ) {
a = 0;
}
int main( void ) {
int x = 5;
azzera( x );
cout << x << endl; // stampa 5 return 0;
}
Moreno Marzolla Fondamenti di Informatica 10
Passaggio per riferimento Passaggio per riferimento
E' anche possibile fare in modo che la modifica del parametro di una funzione si ripercuota sul valore effettivamente passato
Come succede nel caso del passaggio di vettori
In questo caso usiamo il passaggio di parametri per riferimento #include <iostream>
using namespace std;
void azzera( int &a ) {
a = 0;
}
int main( void ) {
int x = 5;
azzera( x );
cout << x << endl; // stampa zero!
return 0;
}
Passaggio per riferimento Passaggio per riferimento
Per passare un parametro per riferimento (cioè per fare in modo che ogni modifica che la funzione fa a quel parametro venga vista
anche al di fuori della funzione) è sufficiente precedere il nome del parametro col simbolo &
Esempio Esempio
Scrivere una funzione scambia() che accetta due parametri a, b di tipo int. La funzione non restituisce alcun risultato, ma scambia tra loro i valori di a e b. In altre parole, la seguente funzione main():
deve stampare 1 5;
// Dichiarazione di scambia() int main( void )
{
int a=5;
int b=1;
scambia( a, b );
cout << a << << b << endl;
return 0;
}
Moreno Marzolla Fondamenti di Informatica 13
Soluzione Soluzione
#include <iostream>
using namespace std;
void scambia( int &a, int &b ) {
int tmp = a;
a = b;
b = tmp;
}
int main( void ) {
int a=5;
int b=1;
scambia( a, b );
cout << a << << b << endl;
return 0;
}
Moreno Marzolla Fondamenti di Informatica 14
Esercizi per domani / 1 Esercizi per domani / 1
Scrivere una funzione inverti() che accetta come parametro un vettore di interi a[] e la sua dimensione dim_a; la funzione inverte gli
elementi di a[] (cioè scambia il primo elemento di a con l'ultimo, il secondo col penultimo ecc.)
Scrivere una funzione main() per testare la inverti() appena realizzata
Moreno Marzolla Fondamenti di Informatica 15
Esercizi per domani / 2 Esercizi per domani / 2
Scrivere una funzione somma_alternata che accetta come parametro un vettore di interi a[] e la sua dimensione dim_a. La funzione calcola la somma alternata di a[], ossia calcola la quantità:
a[0] - a[1] + a[2] - a[3] + a[4] ...
Moreno Marzolla Fondamenti di Informatica 16
Esercizi per domani / 3 Esercizi per domani / 3
Scrivere una funzione fill() che accetta come parametri un vettore di interi a[], la sua dimensione dim_a e un ulteriore intero x compreso tra 0 e 4 (estremi inclusi). La funzione non
restituisce alcun risultato.
La funzione modifica il vettore a[] come segue. Il primo
elemento di a[] viene posto a x, il secondo a x+1 e così via. Ogni volta che il valore assegnato ad un elemento di a raggiunge 4, l'elemento successivo ricomincia da zero
Esempio: se dim_a=10, x=3, allora dopo la chiamata fill( a, dim_a, x ) il vettore deve contenere questi valori
{ 3, 4, 0, 1, 2, 3, 4, 0, 1, 2 };
Esempio: se dim_a=10, x=4, allora dopo la chiamata fill( a, dim_a, x ) il vettore deve contenere questi valori
{ 4, 0, 1, 2, 3, 4, 0, 1, 2, 3 };
Moreno Marzolla Fondamenti di Informatica 17
Cenni alle funzioni ricorsive Cenni alle funzioni ricorsive
Ovviamente è possibile che una funzione f(), al suo interno, richiami un'altra funzione g()
int g( int x ) {
return x+1;
}
int f( int x, int y ) {
return g(x) + g(y);
}
// domanda: cosa calcola f( 3, 4 )?
Moreno Marzolla Fondamenti di Informatica 18
Funzioni ricorsive Funzioni ricorsive
E' anche possibile per una funzione f() richiamare se' stessa
Esempio: come si calcola il fattoriale di un numero non negativo n?
fattoriale( 0 ) = 1
se n>0, fattoriale( n ) = n * fattoriale( n-1 )
Tutto questo si può direttamente implementare in C++
Esempio fattoriale Esempio fattoriale
#include <iostream>
using namespace std;
int fattoriale( int n ) {
if ( n == 0 ) { return 1;
} else {
return n * fattoriale( n-1 );
} }
int main( void ) {
cout << fattoriale( 3 ) << endl; // stampa 3*2*1 = 6 cout << fattoriale( 4 ) << endl; // stampa 4*3*2*1 = 24 return 0;
}
Osservazione Osservazione
Perché la ricorsione funziona?
E' sempre necessario definire almeno un caso base, ossia un caso in cui il valore della funzione è
univocamente determinato senza invocare nuovamente la funzione stessa
nel caso del fattoriale, 0! = 1, per definizione
Ogni volta che la funzione invoca se stessa, è
necessario che lo faccia passando dei parametri che si
avvicinino al caso base
il calcolo del fattoriale di n richiede il calcolo del fattoriale di
n-1, che a sua volta richiede il fattoriale di n-2 finché
inevitabilmente si arriva a calcolare il fattoriale di 0, e qui la
ricorsione si ferma
Moreno Marzolla Fondamenti di Informatica 21
Calcolo del Massimo Comune Divisore Calcolo del Massimo Comune Divisore
Definiamo la funzione MCD( a, b ) che calcola il massimo comune divisore tra due interi non negativi a e b
Se a=b, allora MCD( a, b ) = a (oppure b, tanto sono uguali!)
Se a>b, allora MCD( a, b ) = MCD( a-b, b )
Se b>a, allora MCD( a, b ) = MCD( a, b-a )
Moreno Marzolla Fondamenti di Informatica 22
Soluzione Soluzione
#include <iostream>
using namespace std;
int MCD( int a, int b ) {
if ( a == b ) { return a;
} else {
if ( a > b ) {
return MCD( a-b, b );
} else {
return MCD( a, b-a );
} } }
int main( void ) {
cout << MCD( 3, 4 ) << endl; // stampa 1 cout << MCD( 12, 4 ) << endl; // stampa 4 cout << MCD( 18, 12 ) << endl; // stampa 6 return 0;
}
Moreno Marzolla Fondamenti di Informatica 23
Esercizio per domani Esercizio per domani
Scrivere una funzione ricorsiva che calcola il prodotto tra due interi non negativi a e b come segue:
Se a=1, prodotto( a, b ) = b