tipoRitorno nomeFunzione (arg1, arg2, ..., argN) { /* ...*/ } |
main
che, negli esempi fino ad ora considerati, non torna nessun valore (è dunque una funzione void) e non ha argomenti. All'interno di una funzione deve essere presente lo statement che stabilisce il ritorno di un risultato da parte di essa: si tratta dello statement return, seguito dal risultato da tornare, che deve essere dello stesso tipo del tipo di ritorno della funzione (ovviamente); se la funzione è void allora lo statement return non è obbligatorio, ma può comunque essere utilizzato per interrompere il normale flusso di esecuzione della funzione. Vediamo qualche esempio.
// ex4_4_1.cpp #include <iostream.h> // int max (int a, b) { // NO: bisogna dichiarare gli // /* ... */ // argomenti delle funzioni // } // per esteso int max (int a, int b) { if (a >= b) return a; return b; } void main() { int a, b; cout << "a? "; cin >> a; cout << "b? "; cin >> b; int m = max (a, b); cout << "max: " << m; }
Si noti innanzitutto che abbiamo definito la funzione max
prima del corpo principale; se avessimo voluto definirla dopo di esso, avremmo dovuto dichiararla comunque prima di tale blocco. Qual è la differenza tra dichiarare e definire una funzione? Nella dichiarazione di una funzione si danno solo le informazioni strettamente necessaria: tipo del ritorno e tipo degli argomenti, mentre definire una funzione vuol dire scrivere il suo corpo, e quindi dare anche un nome agli argomenti. Il seguente esempio è del tutto equivalente al precedente:
// ex4_4_2.cpp #include <iostream.h> int max (int, int); // dichiarazione void main() { int a, b; cout << "a? "; cin >> a; cout << "b? "; cin >> b; int m = max (a, b); cout << "max: " << m; } int max (int a, int b) { // definizione if (a >= b) return a; return b; }
In entrambi gli esempi del presente paragrafo abbiamo utilizzato gli stessi identificatori per le variabili all'interno del corpo principale e per quelle interne alle funzioni; i programmi risultano corretti, sebbene sappiamo che non è possibile usare un identificatore già esistente, perché le funzioni, così come i blocchi, hanno una vita ``parallela'' a quella del programma principale: possono ad esempio permettersi di avere gli stessi nomi per le variabili.
Ci poniamo adesso un problema, che prima della presentazione delle funzioni poteva non avere senso: è possibile dichiarare una variabile esternamente a tutte le funzioni, compresa il corpo principale? La risposta è affermativa: si tratta in tal caso di variabili globali, le quali valgono in tutte le funzioni. Analogamente è possibile dichiarare delle costanti globali.
// ex4_4_3.cpp #include <iostream.h> const double PIGRECO = 3.141592; double circ; double circonferenza (double raggio) { // circ appartiene alla funzione double circ = raggio * 2 * PIGRECO; return circ; } void stampaCirconferenza () { cout << "cinconferenza: " << circ; // e' la circ globale } void main() { double raggio; cout << "raggio? "; cin >> raggio; circ = circonferenza (raggio); // e' la circ globale stampaCirconferenza(); }
Si noti in questo esempio come l'identificatore circ
assuma un significato diverso a seconda della funzione nella quale si trovi: in generale esso è riferito ad una variabile globale di tipo double, tuttavia nella funzione circonferenza
, siccome viene dichiarata una nuova variabile circ
di tipo double, la variabile globale risulta nascosta. Questo modo di procedere è evidentemente molto scomodo, nonché pericoloso; è infatti facile confondere una variabile per un'altra, specialmente in programmi corposi; si cerchi pertanto di utilizzare il meno possibile le variabili globali. Vediamo il seguente:
// ex4_4_4.cpp #include <iostream.h> // calcola il massimo comun divisore tra due numeri // sfruttando il cosiddetto algoritmo di Euclide int mcd (int a, int b) { while (a != b) if (a > b) a -= b; else b -= a; return a; } // calcola il minimo comune multiplo tra due numeri // sfruttando il fatto che esso e' uguale al prodotto // dei due numeri diviso il loro massimo comun divisore int mcm (int a, int b) { int m = (a * b) / mcd(a, b); return m; } void stampa (int i) { switch (i) { case 1: // messaggio di benvenuto cout << "questo programma calcola\n" "il massimo comun divisore\n" " e il minimo comune multiplo\n" "tra due numeri interi\n\n"; return; case 2: // messaggio di arrivedersi cout << "bye bye!"; return; default: return; } cout << "AHHHHHH"; // non viene mai stampato } void main () { int a, b; stampa (1); // benvenuto cout << "a? "; cin >> a; cout << "b? "; cin >> b; cout << "mcm: " << mcm(a,b) << '\n'; cout << "mcd: " << mcd(a,b) << '\n'; stampa (2); // arrivederci }
esempio di output:
questo programma calcola
il massimo comun divisore
e il minimo comune multiplo
tra due numeri interi
a? 30
b? 45
mcm: 90
mcd: 15
bye bye!
Si noti che nella funzione void stampa(int)
abbiamo utilizzato la parola chiave return al posto del classico break; mentre quest'ultimo ci avrebbe fatti uscire semplicemente dallo switch, e quindi il programma avrebbe stampato anche AHHHHHHH
, utilizzando return il flusso di esecuzione torna al programma principale, così come era nostra intenzione che fosse.