Menu

Ciclo while in C++: sintassi, do-while e insidie

Il ciclo while del C++ spiegato: il while che controlla prima la condizione, il do-while che viene eseguito almeno una volta, i cicli fino a un valore sentinella, break e continue, e come evitare i cicli infiniti.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Quando non hai un contatore

Il ciclo for è costruito attorno a un contatore che imposti all'inizio. Ma molti cicli non hanno un conteggio preciso: continuare a leggere numeri finché l'input non finisce, continuare a chiedere una password finché non è corretta, continuare a dimezzare un valore finché non arriva a 1. Per questi casi il ciclo while è la scelta naturale: ripete finché una condizione resta vera.

Un ciclo while controlla la condizione prima di ogni passaggio, compreso il primo. Se la condizione è falsa fin dall'inizio, il corpo non viene mai eseguito.

La condizione count > 0 viene controllata per prima; se è vera il corpo viene eseguito, poi si torna indietro e si controlla di nuovo. La riga count-- è quella che prima o poi rende falsa la condizione: toglila e il ciclo gira all'infinito.

Anatomia di un ciclo while

Confrontalo con il ciclo for in tre parti che già conosci. Un ciclo while separa quei tre compiti: l'inizializzazione la fai prima del ciclo, la condizione va tra le parentesi e l'aggiornamento sta dentro il corpo.

int i = 0;          // inizializzazione: prima del ciclo
while (i < 5) {     // condizione: controllata a ogni passaggio
    cout << i << "\n";
    i++;            // aggiornamento: devi ricordartelo tu
}

Quest'ultima parte è il punto critico. In un ciclo for l'aggiornamento sta proprio accanto alla condizione, quindi è difficile dimenticarlo. In un ciclo while è solo un'altra istruzione nel corpo: il bug più comune in assoluto è ometterlo e bloccare il programma.

Un'insidia del C++ che colpisce chi inizia: un punto e virgola di troppo subito dopo la condizione trasforma il corpo in un'istruzione vuota.

int i = 0;
while (i < 5);   // <-- questo punto e virgola è l'intero corpo del ciclo
{
    cout << i << "\n";
    i++;
}

Questo gira all'infinito senza fare nulla, perché il ; è il corpo e i non cambia mai. Il blocco tra graffe verrebbe poi eseguito una sola volta. Il compilatore non ti ferma: è codice perfettamente valido, solo che non è quello che intendevi.

do-while: eseguire il corpo almeno una volta

A volte serve che il corpo venga eseguito una volta prima ancora di poter decidere se ripetere. Il ciclo do-while controlla la condizione in fondo, quindi il corpo viene sempre eseguito almeno una volta:

Devi chiedere e leggere almeno una volta prima di sapere se l'input è valido, ed è esattamente ciò che ti dà do-while. Nota il punto e virgola dopo while (...): in C++ è obbligatorio per do-while, e dimenticarlo è un errore di compilazione frequente.

La differenza rispetto a un semplice while si vede chiaramente quando la condizione è falsa fin dall'inizio:

Viene stampato solo do-while body. Il ciclo while salta del tutto il corpo perché x < 5 era falsa già prima del primo controllo.

Ciclare finché cin non fallisce

Un uso classico di while è leggere finché l'input non si ferma: non c'è un contatore, vai avanti finché lo stream non ti dice di smettere. In C++, cin >> value restituisce lo stream stesso, che vale vero finché la lettura riesce e falso quando raggiunge la fine dell'input o un tipo non corrispondente. Questo lo rende una condizione di ciclo pulita:

La condizione fa doppio lavoro: legge e verifica in un solo passo. Confrontalo con un valore sentinella, ad esempio fermarsi su 0. Lì devi leggere una volta prima del ciclo e di nuovo in fondo a ogni passaggio, così la condizione verifica sempre un input nuovo:

Se dimentichi la seconda lettura dentro il corpo, value non cambia mai e ti ritrovi con un ciclo infinito. La forma while (cin >> value) evita il problema inglobando la lettura nella condizione.

break e continue nei cicli while

break e continue funzionano qui come in un ciclo for. break esce subito dal ciclo; continue torna direttamente al controllo della condizione, saltando il resto del passaggio corrente:

Questo stampa 1 3 5 7 9. Il while (true) volutamente non si ferma mai da solo: il break è l'unica uscita. Fai attenzione a continue in un ciclo while: dato che l'aggiornamento fa parte del corpo, tornare in cima con continue prima di aver fatto avanzare il contatore è un modo silenzioso per bloccare il ciclo. Nell'esempio sopra n++ viene eseguito per primo, quindi è sicuro.

Attenzione ai cicli infiniti

La condizione deve prima o poi diventare falsa, e questo dipende interamente da qualcosa che cambia dentro il corpo. I due colpevoli abituali sono dimenticare l'aggiornamento e aggiornare in un modo che salta oltre il valore di uscita:

int i = 0;
while (i < 5) {
    cout << i << "\n";   // i non cambia mai -> gira per sempre
}
int i = 0;
while (i != 10) {
    i += 3;   // 0, 3, 6, 9, 12... salta oltre il 10 -> gira per sempre
}

Il primo si blocca perché i non viene mai aggiornata. Il secondo si blocca perché il contatore scavalca proprio il valore che la condizione cerca: preferisci < o <= a != quando il passo potrebbe non cadere esattamente sul valore. Un while (true) va bene se ha un break garantito; uno involontario è solo un bug. E ricorda la trappola del corpo vuoto while (...); vista prima: un punto e virgola fuori posto produce un ciclo infinito che a prima vista sembra corretto.

Prossimo: il ciclo for basato su intervallo

Un ciclo while è lo strumento giusto quando cicli finché una condizione non cambia e non c'è un conteggio preciso. Ma quando vuoi semplicemente visitare ogni elemento di un contenitore, un vector, un array, una string, senza indici né condizioni da gestire, il C++ moderno ha qualcosa di più pulito: il ciclo for basato su intervallo (for (auto x : container)). È la prossima pagina.

Domande frequenti

Qual è la differenza tra while e do-while in C++?

Un ciclo while controlla la condizione prima del primo passaggio, quindi il corpo può essere eseguito zero volte. Un ciclo do-while esegue il corpo prima una volta e poi controlla la condizione in fondo, quindi viene sempre eseguito almeno una volta. Usa do-while quando il lavoro deve avvenire prima di poter decidere se ripetere, come chiedere un input e poi validarlo. Nota che do-while richiede un punto e virgola dopo il while (...) di chiusura.

Quando usare un ciclo while invece di un ciclo for in C++?

Usa un ciclo while quando non hai un contatore ben definito e vuoi solo ripetere finché una condizione non cambia: leggere input finché cin non fallisce, attendere finché un valore non è pronto, o elaborare una coda finché non è vuota. Scegli un ciclo for quando conosci il numero di iterazioni o hai un indice ovvio da contare.

Come si ferma un ciclo while infinito in C++?

Assicurati che qualcosa dentro il corpo prima o poi renda falsa la condizione (decrementare un contatore, far avanzare un puntatore, impostare un flag). Per un ciclo while (true) voluto, metti al suo interno un break protetto da un if. Se un ciclo si blocca, di solito la causa è aver dimenticato di aggiornare la variabile da cui dipende la condizione.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA