Controllo del flusso
Esamineremo ora le istruzioni per il controllo del flusso, ovvero quelle istruzioni
che consentono di eseguire una certa sequenza di istruzioni, o eventualmente
un'altra, in base al valore di una espressione booleana.
IF-ELSE
L'istruzione condizionale if-else ha due possibili formulazioni:
if ( <Condizione> ) <Istruzione1>
;
oppure
if ( <Condizione> ) <Istruzione1>
;
else <Istruzione2> ;
L'else e` quindi opzionale, ma, se utilizzato, nessuna
istruzione deve essere inserita tra il ramo if e il ramo
else . Vediamo ora la semantica di tale istruzione.
In entrambi i casi se Condizione e` vera viene eseguita Istruzione1,
altrimenti nel primo caso non viene eseguito alcunche`, nel secondo caso invece
si esegue Istruzione2.
Si osservi che Istruzione1 e Istruzione2 sono istruzioni singole
(una sola istruzione), se e` necessaria una sequenza di istruzioni esse devono
essere racchiuse tra una coppia di parentesi graffe { }, come mostra
il seguente esempio (si considerino X, Y e Z variabili intere):
if ( X==10 ) X--;
else { //
istruzione composta
Y++;
Z*=Y;
}
Ancora alcune osservazioni: il linguaggio prevede che due istruzioni consecutive
siano separate da ; (punto e virgola), in particolare si noti il punto
e virgola tra il ramo if e l'else ; l'unica
eccezione alla regola e` data dalle istruzioni composte (cioe` sequenze di istruzioni
racchiuse tra parentesi graffe) che non devono essere seguite dal punto e virgola
(non serve, c'e` la parentesi graffa).
Per risolvere eventuali ambiguita` il compilatore lega il ramo else
con la prima occorrenza libera di if che incontra tornando
indietro (si considerino Pippo, Pluto e Topolino variabili
intere):
if (Pippo) if (Pluto) Topolino = 1;
else Topolino = 2;
viene interpretata come
if (Pippo)
if (Pluto) Topolino = 1;
else Topolino = 2;
l'else viene cioe` legato al secondo if .
WHILE & DO-WHILE
I costrutti while e do while consentono l'esecuzione ripetuta
di una sequenza di istruzioni in base al valore di verita` di una condizione.
Vediamone la sintassi:
while ( <Condizione> ) <Istruzione>
;
Al solito, Istruzione indica una istruzione singola, se e` necessaria
una sequenza di istruzioni essa deve essere racchiusa tra parentesi graffe.
La semantica del while e` la seguente: prima si valuta Condizione
e se essa e` vera (true) si esegue Istruzione e poi si ripete il tutto;
l'istruzione termina quando Condizione valuta a false.
Esaminiamo ora l'altro costrutto:
do <Istruzione;> while
( <Condizione> ) ;
Nuovamente, Istruzione indica una istruzione singola, se e` necessaria
una sequenza di istruzioni essa deve essere racchiusa tra parentesi graffe.
Il do while differisce dall'istruzione while
in quanto prima si esegue Istruzione e poi si valuta Condizione,
se essa e` vera si riesegue il corpo altrimenti l'istruzione termina; il corpo
del do while viene quindi eseguito sempre almeno una volta.
Ecco un esempio:
// Calcolo del fattoriale tramite while
if (InteroPositivo) {
Fattoriale = InteroPositivo;
while (--InteroPositivo)
Fattoriale *= InteroPositivo;
}
else Fattoriale = 1;
// Calcolo del fattoriale tramite do-while
Fattoriale = 1;
if (InteroPositivo)
do
Fattoriale *= InteroPositivo;
while (--InteroPositivo);
IL CICLO FOR
Come i piu` esperti sapranno, il ciclo for e` una specializzazione del
while, tuttavia nel C++ la differenza tra for e while e`
talmente sottile che i due costrutti possono essere liberamente scambiati tra
loro.
La sintassi del for e` la seguente:
for ( <Inizializzazione> ; <Condizione>
; <Iterazione> )
<Istruzione> ;
Inizializzazione puo` essere una espressione che inizializza le variabili
del ciclo o una dichiarazione di variabili (nel qual caso le veriabili dichiarate
hanno scope e lifetime limitati a tutto il ciclo); Condizione e` una
qualsiasi espressione booleana; e Iterazione e` una istruzione da eseguire
dopo ogni iterazione (solitamente un incremento). Tutti e tre gli elementi appena
descitti sono opzionali, in particolare se Condizione non viene specificata
si assume che essa sia sempre verificata.
Ecco la semantica del for espressa tramite while
(a meno di una istruzione continue contenuta in Istruzione):
<Inizializzazione> ;
while ( <Condizione> ) {
<Istruzione> ;
<Iterazione> ;
}
Una eventuale istruzione continue (vedi di seguito) in
Istruzione causa un salto a Iterazione nel caso del ciclo for ,
nel while invece causa un salto all'inizio del ciclo.
Ecco come usare il ciclo for per calcolare il fattoriale:
for (Fatt = IntPos? IntPos : 1; IntPos > 1; /*
NOP */)
Fatt *= (--IntPos);
Si noti la mancanza del terzo argomento del for , omesso
in quanto inutile.
BREAK & CONTINUE
Le istruzioni break e continue consentono un maggior controllo
sui cicli. Nessuna delle due istruzioni accetta argomenti. L'istruzione break
puo` essere utilizzata dentro un ciclo o una istruzione switch (vedi
paragrafo successivo) e causa la terminazione del ciclo in cui occorre (o dello
switch). L'istruzione continue puo` essere utilizzata solo dentro
un ciclo e causa l'interruzione della corrente esecuzione del corpo del ciclo;
a differenza di break quindi il controllo non viene passato all'istruzione
successiva al ciclo, ma al punto immediatamente prima della fine del corpo del
ciclo (pertanto il ciclo potrebbe ancora essere eseguito):
Fattoriale = 1;
while (true) {
// all'infinito...
if (InteroPositivo > 1) {
Fattoriale *= InteroPositivo--;
continue;
}
break; // se InteroPositivo
<= 1
//
continue provoca un salto in questo punto
}
SWITCH
L'istruzione switch e` molto simile al case del Pascal (anche
se piu` potente) e consente l'esecuzione di uno o piu` frammenti di codice a
seconda del valore di una espressione:
switch ( <Espressione> ) {
case <Valore1> : <Istruzione>
;
/* ... */
case <ValoreN> : <Istruzione>
;
default : <Istruzione> ;
}
Espressione e` una qualunque espressione capace di produrre un valore
intero; Valore1...ValoreN sono costanti a valori interi; Istruzione
e` una qualunque sequenza di istruzioni (non racchiuse tra parentesi graffe).
All'inizio viene valutata Espressione e quindi viene eseguita l'istruzione
relativa alla clausola case che specifica il valore prodotto
da Espressione; se nessuna clausola case specifica
il valore prodotto da Espressione viene eseguita l'istruzione relativa
a default qualora specificato (il ramo default
e` opzionale).
Ecco alcuni esempi:
switch (Pippo) {
case 1 :
Topolino = 5;
case 4 :
Topolino = 2;
Clarabella = 7;
default :
Topolino = 0;
}
switch (Pluto) {
case 5 :
Pippo = 3;
case 6 :
Pippo = 5;
case 10 :
Orazio = 20;
Tip = 7;
}
// niente caso default
Il C++ (come il C) prevede il fall-through automatico tra le clausole dello
switch , cioe` il controllo passa da una clausola case
alla successiva (default compreso) anche quando la clausola
viene eseguita. Per evitare cio` e` sufficiente terminare le clausole con break
in modo che, alla fine dell'esecuzione della clausola, termini anche lo switch :
switch (Pippo) {
case 1 :
Topolino = 5; break;
case 4 :
Topolino = 2;
Clarabella = 7; break;
default :
Topolino = 0;
}
GOTO
Il C++ prevede la tanto deprecata istruzione goto per eseguire salti
incondizionati. La cattiva fama del goto deriva dal fatto che il suo
uso tende a rendere obiettivamente incomprensibile un programma; tuttavia in
certi casi (tipicamente applicazioni real-time) le prestazioni sono assolutamente
prioritarie e l'uso del goto consente di ridurre al minimo i tempi. Comunque
quando possibile e` sempre meglio evitarne.
L'istruzione goto prevede che l'istruzione bersaglio del salto sia etichettata
tramite un identificatore utilizzando la sintassi
<Etichetta> : <Istruzione>
che serve anche a dichiarare Etichetta.
Il salto ad una istruzione viene eseguito con
goto <Etichetta> ;
ad esempio:
if (Pippo == 7) goto PLUTO;
Topolino = 5;
/* ... */
PLUTO : Pluto = 7;
Si noti che una etichetta puo` essere utilizzata anche prima di essere dichiarata.
Esiste una limitazione all'uso del goto : il bersaglio dell'istruzione
(cioe` Etichetta) deve trovarsi all'interno della stessa funzione dove
appare l'istruzione di salto.
|