Menu

Ciclo do while in C: sintassi, esempi e quando usarlo

Il ciclo del C che esegue prima il corpo: come do-while garantisce un passaggio prima del test, perché finisce con un punto e virgola, gli schemi di menu e di nuovo tentativo per cui è nato e come si differenzia da un semplice while.

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

Il ciclo che viene eseguito sempre una volta

Un ciclo while verifica prima di agire, quindi può essere eseguito zero volte. Di solito è giusto così. A volte è esattamente sbagliato: non puoi sapere se ripetere una richiesta finché non l'hai mostrata, e non puoi giudicare l'input di un utente finché non ne hai letto un po'. do-while sposta il test alla fine, quindi il corpo viene eseguito per primo e la condizione decide solo se ripeterlo ancora.

La condizione i < 5 è falsa fin dall'inizio. Il ciclo while viene eseguito zero volte; il do-while esattamente una. È tutta qui la differenza tra i due.

Sintassi, e quel punto e virgola

do {
    // corpo: viene sempre eseguito almeno una volta
} while (condition);

L'ordine si legge come si esegue: fai (do) il corpo e, finché (while) la condizione è ancora vera, rifallo.

Il punto e virgola dopo la parentesi di chiusura è obbligatorio. do ... while (cond); è una sola istruzione, e le istruzioni C terminano con il punto e virgola. Se lo ometti il compilatore continua a leggere e poi segnala un errore di sintassi da qualche parte più sotto: ecco perché l'errore vero spesso si trova a diverse righe da quella indicata.

È anche l'unico punto del C in cui while (cond); con il punto e virgola è corretto e non un bug. In un normale ciclo while la stessa punteggiatura crea un corpo vuoto e di solito un ciclo infinito; qui invece chiude un do.

Le graffe sono facoltative per un corpo di una sola istruzione ma, come per ogni altra struttura di controllo del C, scrivile comunque.

Lo schema di validazione dell'input

È per questo che do-while è stato pensato. Devi leggere qualcosa prima di poter dire se è accettabile, quindi la lettura deve avvenire prima del test:

Il ciclo continua a leggere finché un valore non passa, e la stessa condizione che rifiuta un valore errato è quella che richiede un altro passaggio. Scritto come while, la lettura dovrebbe comparire due volte, una prima del ciclo per preparare la condizione e una alla fine del corpo: è proprio la duplicazione che do-while elimina.

Con un input reale il corpo chiamerebbe invece scanf:

int age;
do {
    printf("Inserisci la tua eta' (1-120): ");
    if (scanf("%d", &age) != 1) {
        while (getchar() != '\n') { }   /* scarta la riga non valida */
        age = -1;                        /* forza un altro passaggio */
    }
} while (age < 1 || age > 120);

Nota il while interno che svuota il resto della riga. Se scanf non riesce a convertire, il testo che ha causato l'errore resta nel buffer di input e anche ogni lettura successiva fallisce su di esso: un ciclo che gira all'infinito stampando la richiesta. Svuotarlo fa parte dello schema.

Lo schema del menu

L'altro uso classico: mostra le opzioni, leggi una scelta, esegui l'azione e ripeti finché l'utente non esce. Il menu deve comparire prima che ci sia una scelta da verificare.

break dentro lo switch termina lo switch, non il ciclo: un punto su cui conviene essere precisi, visto che entrambi usano la stessa parola chiave. Qui il ciclo termina perché choice != 4 diventa falso. Se volessi davvero uscire dal ciclo dall'interno dello switch, la strada sarebbe return o una variabile flag; break da solo non può farlo.

Un primo passaggio garantito può essere un bug

Poiché il corpo viene eseguito prima di qualsiasi test, do-while elabora tranquillamente dati che non esistono:

/* BUG: stampa a[0] anche quando n vale 0 */
int i = 0;
do {
    printf("%d\n", a[i]);
    i++;
} while (i < n);

Con n == 0 questo legge a[0] su un array vuoto: comportamento indefinito. Qualsiasi ciclo su una collezione che potrebbe essere vuota vuole un while o un for, in cui il test viene prima.

La regola pratica: usa do-while solo quando un'esecuzione con zero iterazioni è impossibile per la natura del problema, non semplicemente improbabile. Chiedere qualcosa all'utente, lanciare dadi finché non compare un obiettivo, generare e verificare un candidato: queste cose davvero non si possono giudicare prima del primo passaggio. Percorrere una lista non può dire lo stesso.

break e continue in un do-while

Funzionano entrambi, e continue ha una particolarità da conoscere: salta al test della condizione, non all'inizio del corpo.

L'i++ in cima al corpo viene eseguito a ogni passaggio, compresi quelli interrotti da continue, quindi il ciclo avanza comunque. Metti l'aggiornamento dopo un continue e il ciclo si blocca: la stessa trappola dei cicli while.

break esce subito dal ciclo e salta del tutto la condizione.

Scegliere tra i tre cicli

I tre cicli del C sono ugualmente potenti; la scelta riguarda quale esprime meglio l'intenzione.

for        un contatore, il suo limite e il suo passo stanno insieme: "n volte"
while      ripeti finché una condizione cambia, magari mai: "finché"
do-while   lo stesso, ma il primo passaggio è garantito: "almeno una volta"

In pratica do-while è di gran lunga il più raro dei tre. La maggior parte dei cicli o conta o deve gestire il caso vuoto, ed entrambe le cose vogliono il test in cima. Usa do-while quando ti accorgi di duplicare un'istruzione subito prima di un ciclo while per preparare la sua condizione: quella duplicazione è il segnale.

Domande frequenti

Come si scrive un ciclo do-while in C?

do { body } while (condition);: prima il corpo, poi il test, e l'intera istruzione termina con un punto e virgola. Il corpo viene sempre eseguito almeno una volta, poi si ripete finché la condizione è diversa da zero.

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

Dove si trova il test. Un ciclo while controlla la condizione prima del primo passaggio, quindi può essere eseguito zero volte. Un do-while controlla dopo, quindi viene sempre eseguito almeno una volta. Scegli do-while solo quando quel primo passaggio garantito è davvero ciò che serve al problema.

Perché un ciclo do-while ha bisogno di un punto e virgola alla fine?

Perché do ... while (cond); è una sola istruzione e, come ogni altra istruzione C, termina con un punto e virgola. Ometterlo produce un errore di sintassi confuso che indica la riga successiva, perché il compilatore continua a leggere in cerca del resto dell'istruzione.

Quando conviene usare un ciclo do-while?

Quando il corpo deve essere eseguito prima che tu possa sapere se ripetere: mostrare un menu prima di leggere una scelta, richiedere di nuovo l'input finché non è valido, oppure generare un valore e poi verificarlo. Se la condizione si può controllare prima, un ciclo while lo esprime in modo più semplice.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA