next up previous contents index
Next: Interruzione di un ciclo Up: Costrutti condizionali e iterativi Previous: Costrutti ciclici: for   Indice   Indice analitico

Costrutti ciclici: while e do ...while

Trattiamo ora altri due cicli, molto simili tra di loro; essi sono il ciclo while e il ciclo do ...while, le cui sintassi sono:
while (condizione) statement
do statement while (condizone);

ove statement indica il corpo dei due cicli; l'unica differenza presente tra di essi è che il costrutto do ...while esegue almeno una volta il ciclo, mentre while, nel caso la condizione sia falsa in partenza, non entra affatto nel ciclo. Come per il for, è possibile cadere in cicli infiniti. Mostriamo alcuni esempi:


// ex3_4_1.cpp
// mostra l'eco di numeri interi
// fino a quando non si immette 0
#include <iostream.h>
void main() {
   int n = 1;         // dummy value
   while (n != 0) {
      cout << "? ";
      cin >> n;
      cout << n << "\n";
   }
}

Si noti che, affinché il ciclo venga eseguito almeno una volta, è necessario inizializzare la variabile di controllo n con un valore non-zero arbitrario; in casi simili è calorosamente consigliabile inserire un commento specificando che il valore inserito si tratta di un dummy value, cioè di un valore che non ha alcun significato di per sé, ma che serve solo come ``trucco'' di programmazione. Un programma equivalente, e senz'altro più pulito stilisticamente, è il seguente:


// ex3_4_2.cpp
// equivalente di ex3_4_1.cpp
#include <iostream.h>
void main() {
   int n;
   do {
      cout << "? ";
      cin >> n;
      cout << n << "\n";
   }
}

Si può dimostrare facilmente che uno qualunque dei tre costrutti iterativi del C++ è equivalente sintatticamente ad un altro; proponiamo tre programmi del tutto equivalenti che stampano il seno degli angoli compresi tra $0$ e $2\pi$, con un incremento di $\frac{\pi}{4}$ radianti; per utilizzare la funzione sin dobbiamo includere, come già fatto per la funzione sqrt, la libreria matematica math.h.


// ex3_4_3.cpp
#include <iostream.h>
#include <math.h>
void main () {
   double pi = 3.141592;
   double x = 0;
   do {
      cout << "\n sin(" << x << ") = " << sin(x);
      x += pi / 4;
   } while (x <= 2*pi);
}


// ex3_4_4.cpp
#include <iostream.h>
#include <math.h>
void main () {
   double pi = 3.141592;
   double x = 0;
   while (x <= 2 * pi) {
      cout << "\n sin(" << x << ") = " << sin(x);
      x += pi / 4;
   }
}


// ex3_4_5.cpp
#include <iostream.h>
#include <math.h>
void main () {
   double pi = 3.141592;
   for ( double x = 0; x <= 2 * pi; x += (pi / 4) )
      cout << "\n sin(" << x << ") = " << sin(x);
}

output:
sin(0) = 0
sin(0.785398) = 0.707107
sin(1.5708) = 1
sin(2.35619) = 0.707107
sin(3.14159) = 6.5359e-07
sin(3.92699) = -0.707106
sin(4.71239) = -1
sin(5.49779) = -0.707108
sin(6.28318) = -1.30718e-06

I tre cicli degli esempi appena esposti si basano tutti sull'utilizzo di una variabile reale come contatore, la qual cosa spesso non è una idea felice: a causa degli errori che il calcolatore commette nell'approssimazione dei numeri reali, si possono verificare delle brutte sorprese; si noti ad esempio che il seno di $2\pi$ (ultima riga di output) non è $0$ come ci si aspetta bensì $-1.30718 \cdot 10^{-6}$, cioè un valore che gli si avvicina molto. Se noi, ad esempio, abbiamo il seguente ciclo:


for (int i = 0; i != 4; i++)
   /* corpo del for */
siamo sicuri che il corpo del for verrà iterato quattro volte; al contrario il seguente ciclo

for (double x = 0; x != pi; x+= (pi / 4))
   /* corpo del for */
è probabilmente infinito, perché pi / 4 + pi / 4 + pi / 4 + pi / 4 è quasi sicuramente diverso da pi; tali errori sono insidiosi, perché noi siamo istintivamente portati a pensare che $\frac{\pi}{4} + \frac{\pi}{4} + \frac{\pi}{4} + \frac{\pi}{4}$ sia uguale $\pi$.

Abbiamo notato che i cicli do, while e for sono del tutto equivalenti sintatticamente; per quale motivo esiste nel linguaggio questa ridondanza? Come in tutti i casi, il motivo riguarda l'estetica del codice e la facilità di programmazione: ciascun ciclo, se usato correttamente, rende il programma più leggibile e intuitivo dello stesso programma scritto utilizzando uno qualunque degli altri costrutti alternativi. Come criterio del tutto generale, possiamo dire che il ciclo for viene utilizzato quando è noto a priori il numero di iterazioni da effettuare, il ciclo while in tutti gli altri casi, esclusi quelli in cui sia necessario effettuare il corpo del ciclo almeno una volta (vd. ex3_4_2.cpp), per i quali conviene utilizzare il ciclo do ...while.


next up previous contents index
Next: Interruzione di un ciclo Up: Costrutti condizionali e iterativi Previous: Costrutti ciclici: for   Indice   Indice analitico
Claudio Cicconetti
2000-09-06