Ciclo While in Linguaggio C

Il ciclo while è una struttura di controllo del flusso che consente di eseguire ripetutamente un blocco di codice fintanto che una determinata condizione viene valutata come vera.

La condizione viene valutata all'inizio di ogni iterazione del ciclo, e se viene valutata come vera, il codice all'interno del blocco viene eseguito. Se la condizione viene valutata come falsa, il ciclo viene interrotto e l'esecuzione del programma prosegue con l'istruzione che segue il ciclo.

Concetti Chiave
  • L'istruzione while permette di eseguire un blocco di codice ripetutamente fintanto che una determinata condizione viene valutata come vera;
  • La condizione viene valutata all'inizio di ogni iterazione del ciclo;
  • Può essere possibile che il codice all'interno del ciclo non venga mai eseguito se la condizione viene valutata come falsa fin dall'inizio;
  • È importante assicurarsi che la condizione venga modificata in qualche modo all'interno del ciclo, altrimenti il ciclo diventerà infinito.

Istruzione while

L'istruzione while rappresenta il più semplice e fondamentale modo per implementare un ciclo in linguaggio C.

Nella sua forma più semplice l'istruzione while ha la seguente sintassi:

while ( espressione ) istruzione;

L'espressione tra parentesi rappresenta l'espressione di controllo mentre l'istruzione che segue rappresenta il corpo del ciclo.

Utilizzando un diagramma di flusso possiamo rappresentare l'istruzione while in questo modo:

Diagramma di flusso dell'istruzione while
Figura 1: Diagramma di flusso dell'istruzione while

Prendiamo un esempio:

while (x > y)   /* Espressione di controllo */
    x = x / 2;  /* Corpo del ciclo */

La prima cosa da notare è che le parentesi sono obbligatorie e che sono immediatamente seguite dal corpo del ciclo.

Quando un'istruzione while viene eseguita, l'espressione di controllo viene valutata per prima. Se il suo valore è diverso da zero, quindi è vera, il corpo del ciclo viene eseguito e l'espressione viene valutata di nuovo. Il processo continua in questo modo, quindi controllando dapprima l'espressione e poi eseguendo il corpo, fino a che l'espressione di controllo non risulta falsa, ossia pari a zero.

Prendiamo l'esempio seguente: questo codice calcola la più piccola potenza di 3 maggiore o uguale ad un numero n.

1
2
3
4
p = 1;
while (p < n)
    p = p * 3;
printf("%d\n", p);

Proviamo ad esaminare cosa accade in questo caso se la variabile n vale 30. Eseguiamo il codice passo passo:

  1. Riga 1: viene assegnato il numero 1 alla variabile p;
  2. Riga 2: l'espressione p < n è vera in quanto 1 \leq 30;
  3. Riga 3: viene assegnato a p il valore p * 3, ossia 3;
  4. Riga 2: l'espressione p < n è vera in quanto 3 \leq 30;
  5. Riga 3: viene assegnato a p il valore p * 3, ossia 3 \cdot 3 = 9;
  6. Riga 2: l'espressione p < n è vera in quanto 9 \leq 30;
  7. Riga 3: viene assegnato a p il valore p * 3, ossia 9 \cdot 3 = 27;
  8. Riga 2: l'espressione p < n è vera in quanto 27 \leq 30;
  9. Riga 3: viene assegnato a p il valore p * 3, ossia 27 \cdot 3 = 81;
  10. Riga 2: l'espressione p < n è falsa in quanto 81 &gt; 30;
  11. Riga 4: si esce dal ciclo e si esegue l'istruzione printf("%d\n", p);. Quindi viene stampato a schermo il valore 81.

Da notare come il ciclo continua ad essere eseguito fintanto che l'espressione di controllo, p <= n è vera. Quando l'espressione risulta falsa, il ciclo termina, e il valore di p risulta essere maggiore o uguale di n come richiesto dalle specifiche del programma.

L'esempio di sopra può essere rappresentato con un diagramma di flusso in questo modo:

Diagramma di flusso dell'esempio
Figura 2: Diagramma di flusso dell'esempio

Anche se il corpo del ciclo deve essere un'istruzione singola, possiamo sempre costruire cicli con più di un'istruzione utilizzando le istruzioni composte e racchiudendo le istruzioni tra parentesi graffe. Ad esempio, possiamo scrivere del codice in questo modo:

while (x > n) {
    printf("%d\n", x);
    x--;
}

Spesso si tende ad utilizzare le parentesi graffe anche per corpi del ciclo composti da una singola istruzione quando ciò non sarebbe necessario, ad esempio:

while (p < n) {
    p = p * 3;
}

Ricapitolando:

Definizione

Istruzione while

Attraverso l'istruzione while è possibile implementare cicli iterativi in linguaggio C. La sintassi generale è la seguente:

while ( condizione ) istruzione;

Fintanto che la condizione condizione risulta vera verrà eseguita l'istruzione istruzione. Quando la condizione condizione risulta falsa, il ciclo termina.

Osservazioni sull'istruzione while

Partiamo da un esempio per fare alcune osservazioni sull'istruzione while.

Supponiamo di voler implementare un programma che stampi a video un conto alla rovescia partendo da 10. Possiamo implementare il programma in questo modo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <stdio.h>

int main() {
    int n = 10;
    while (n > 0) {
        printf("%d\n", n);
        n--;
    }
    printf("Partenza!\n");
    return 0;
}

Se proviamo a compilare ed eseguire questo programma otteniamo l'output seguente:

10
9
8
7
6
5
4
3
2
1
Partenza!

Prima che l'istruzione while venga eseguita, alla variabile n viene assegnato il valore 10 alla riga 4. Successivamente, alla riga 5, viene valutata la condizione che risulta essere vera, in quanto 10 è maggiore di 0. Quindi viene eseguita la riga 6, che stampa il valore corrente di n, e la riga 7 che decrementa n. La condizione viene valutata di nuovo, adesso n vale 9 e la condizione è ancora vera. Per cui le righe 6 e 7 verranno eseguite di nuovo e così via. Tutto questo finché n vale zero, la condizione risulta falsa e il ciclo termina.

La prima osservazione da fare è la seguente:

Definizione

La condizione di controllo di un'istruzione while risulta falsa quando si esce dal ciclo.

Può sembrare un'ovvietà ma si tratta di una proprietà fondamentale dei cicli while. Quando si esce da un ciclo while la condizione risulta sempre falsa, questo perché altrimenti il programma rimarrebbe ancora nel ciclo.

Tornando all'esempio, quando il programma raggiunge la riga 9, la condizione n > 0 deve essere per forza falsa, altrimenti il ciclo continuerebbe la sua esecuzione.

La seconda osservazione da fare è la seguente:

Definizione

Il corpo di un ciclo while potrebbe non essere mai eseguito.

Dal momento che l'espressione di controllo viene valutata prima di eseguire il ciclo, potrebbe accadere che il corpo del ciclo non venga eseguito nemmeno una volta. Questo accade se la condizione risulta già falsa prima ancora di eseguire l'istruzione while la prima volta.

Tornando all'esempio di prima, se invece di assegnare il valore 10 alla variabile n avessimo assegnato il valore -1, giunti alla riga 5 la condizione sarebbe già falsa, per cui le righe 6 e 7 non verrebbero eseguite.

Ad esempio, modificando il programma in questo modo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <stdio.h>

int main() {
    int n = -1;
    while (n > 0) {
        printf("%d\n", n);
        n--;
    }
    printf("Partenza!\n");
    return 0;
}

Il risultato che otteniamo è il seguente:

Partenza!

Infine, l'ultima e più importante osservazione sui cicli while è la seguente:

Nota

All'interno di un ciclo while bisogna inserire una o più istruzioni che agiscano sulla condizione.

Se all'interno di un ciclo while mancano istruzioni che modificano la condizione di controllo quello che accade è che il ciclo while non termina mai. Quello che si ottiene è un ciclo infinito.

Sebbene a volte questo comportamento è quello desiderato, come vedremo nella prossima sezione, è buona prassi non dimenticare mai di inserire istruzioni che modificano la condizione di controllo.

Cicli infiniti

Se l'espressione di controllo di un'istruzione while non risulta mai avere un valore diverso da zero, il ciclo non termina mai. Spesso, in linguaggio C si costruisce deliberatamente un ciclo infinito utilizzando una costante diversa da zero come espressione di controllo:

/* Ciclo infinito */
while (1) {
    /* ... */
}

Un ciclo while scritto in questo modo si esegue all'infinito a meno che non contenga al suo interno istruzioni (come break, return o goto) che trasferiscono il controllo di flusso all'esterno del ciclo, oppure se vengono invocate funzioni che terminano il programma. Nelle prossime lezioni vedremo come fare per uscire da un loop infinito.

Ci sono alcune situazioni in cui può essere utile utilizzare un ciclo while infinito, ovvero un ciclo che viene eseguito ripetutamente senza mai interrompersi. Ecco alcuni esempi di casi in cui può essere utile utilizzare un ciclo infinito:

  1. Quando si vuole creare un programma che resti in esecuzione in modo continuativo, ad esempio un programma che monitora costantemente l'input di un utente o un server che accetta richieste di connessione in modo continuo.
  2. In generale, quando si vuole realizzare un programma che deve reagire a eventi esterni oppure che deve monitorare e misurare fenomeni esterni. Ad esempio un programma di un sistema di misura.

Un esempio di "programma" che utilizza cicli infiniti è un sistema operativo. Un sistema operativo rimane in attesa di eventi esterni che possono essere input dell'utente o eventi hardware ed esegue dei task in risposta. Terminati questi task, il sistema operativo rimane in attesa finché non riceve notifica di altri eventi. Soltanto su richiesta esplicita di spegnimento un sistema operativo termina le proprie operazioni ed esce dal ciclo infinito.

Nelle prossime lezioni vedremo come è possibile uscire da un ciclo.

In Sintesi

In questa lezione abbiamo studiato l'istruzione while e abbiamo visto come usarla per realizzare cicli.

L'istruzione while valuta una condizione all'inizio di ogni iterazione e:

  • se la condizione risulta vera esegue le istruzioni contenute all'interno del ciclo;
  • se la condizione risulta falsa passa all'istruzione immediatamente successiva al ciclo stesso.

Per queste sue caratteristiche, potrebbe accadere che il corpo di un ciclo while non venga eseguito nemmeno una volta. Questo accade quando la condizione risulta falsa già prima della prima iterazione. Oppure, potrebbe accadere la situazione opposta, ossia che il ciclo non termini mai quando la condizione risulta sempre vera ottenendo così un ciclo infinito.

Nelle prossime lezioni vedremo come realizzare cicli utilizzando diverse istruzioni del linguaggio C.