Menu

Ciclo for in C++: sintassi, esempi ed errori comuni

Come ripetere del codice con il ciclo for del C++: l'intestazione in tre parti, contare in avanti e all'indietro, scorrere gli array, i cicli annidati, break e continue, e gli errori di uno e degli unsigned che colpiscono tutti.

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

Perché un ciclo for

Uno switch sceglie un ramo da eseguire una volta. Ma i programmi reali devono fare qualcosa ripetutamente: stampare ogni punteggio, sommare una lista di numeri, disegnare 10 righe di una griglia. Il ciclo for è il cavallo di battaglia del C++ per ripetere codice un numero noto di volte, con un contatore integrato che controlli tu.

Tutto ciò che serve a un ciclo for sta in un'unica intestazione compatta, quindi tutta la storia del "quante volte e come" è visibile a colpo d'occhio.

L'intestazione in tre parti

L'intestazione di un ciclo for ha tre parti separate da punto e virgola: un'inizializzazione, una condizione e un aggiornamento.

for (initializer; condition; update) {
    // corpo: viene eseguito finché la condizione è vera
}

Vengono eseguite in un ordine preciso: l'inizializzazione una volta sola all'inizio; poi la condizione viene controllata prima di ogni iterazione; il corpo viene eseguito solo se la condizione è true; e l'aggiornamento viene eseguito alla fine di ogni iterazione, subito prima che la condizione venga controllata di nuovo.

Qui int i = 0 viene eseguito una volta. Poi si controlla i < 5: finché è vera, il corpo stampa e i++ incrementa il contatore. Quando i arriva a 5 la condizione è false, quindi il ciclo termina e viene stampato done. Il corpo viene eseguito esattamente 5 volte, con i che assume i valori da 0 a 4.

Dichiarare il contatore nell'intestazione (int i = 0) limita lo scope di i al ciclo: dopo la graffa di chiusura non esiste più, ed è esattamente ciò che vuoi.

Contare in avanti, all'indietro e a passi

La parte di aggiornamento non si limita a i++. Puoi contare all'indietro, avanzare di qualsiasi quantità o scorrere l'indice di un array.

Il primo ciclo gira finché i > 0, decrementando ogni volta, quindi stampa 5 4 3 2 1. Il secondo aggiunge 2 a ogni passaggio e usa <= 10 perché 10 è un valore che vogliamo includere. Abbina la condizione all'aggiornamento: contare all'indietro va con > o >=, contare in avanti con < o <=.

Scorrere un array

L'uso più comune di un ciclo di conteggio è percorrere un array tramite indice. Il contatore funge anche da posizione che leggi.

Nota che la condizione è i < n, non i <= n. Un array di 5 elementi ha indici validi da 0 a 4; l'indice 5 è oltre la fine. Leggere scores[5] è comportamento indefinito: potrebbe stampare spazzatura, far crashare il programma o sembrare funzionare e corrompere la memoria in silenzio. Lo schema i < n è la scelta sicura per qualsiasi array con indici a partire da zero.

Se ti servono solo i valori e non l'indice, un for basato su range è più pulito. Usa il classico ciclo con indice quando ti serve davvero la posizione.

break e continue

Due parole chiave ti permettono di cambiare il flusso a metà ciclo. break esce subito dal ciclo; continue salta il resto dell'iterazione corrente e passa all'aggiornamento.

Il primo ciclo si ferma nel momento in cui trova 7 e non controlla il resto. Il secondo usa continue per saltare la stampa del corpo ogni volta che i è pari: l'aggiornamento i++ viene comunque eseguito, quindi il ciclo continua ad avanzare. Un'insidia sottile: continue salta all'aggiornamento, quindi se usi continue in un ciclo il cui contatore viene aggiornato dentro il corpo invece che nell'intestazione, puoi saltare per sbaglio quell'aggiornamento e girare all'infinito.

Cicli annidati

Metti un for dentro un altro per lavorare con griglie, tabelle o coppie. Il ciclo interno viene eseguito per intero a ogni singolo passo del ciclo esterno.

Questo stampa una tabellina 3x3. Il ciclo esterno fissa una riga (row), quello interno percorre ogni colonna (col) di quella riga, poi un a capo chiude la riga. Dai ai contatori nomi distinti (row/col, non i/i): riusare lo stesso nome nasconde quello esterno e produce bug sconcertanti. Fai attenzione anche al costo: annidare un ciclo di n passi dentro un altro di n passi esegue il corpo n * n volte, e cresce in fretta.

Insidie comuni

Poche trappole causano la maggior parte dei bug nei cicli for in C++:

  • Errore di uno: i <= n con una dimensione che parte da zero legge un elemento oltre la fine. Usa i < n.
  • Underflow degli unsigned: contando all'indietro con un tipo unsigned non si va mai sotto zero. for (size_t i = n - 1; i >= 0; i--) gira all'infinito, perché i >= 0 è sempre vera per un valore unsigned: quando i vale 0, i-- ricomincia da un numero positivo enorme. Usa un int signed per i conteggi all'indietro, oppure riscrivi la condizione.
  • Modificare il contatore dentro il corpo: cambiare i sia nel corpo sia nell'intestazione rende imprevedibile il numero di iterazioni. Scegli un solo punto.
// BUG: infinite loop - unsigned i is never < 0
for (size_t i = n - 1; i >= 0; i--) {
    process(arr[i]);
}

I contatori a virgola mobile sono un altro pericolo silenzioso: for (double x = 0.0; x != 1.0; x += 0.1) potrebbe non arrivare mai esattamente a 1.0, perché 0.1 non si può memorizzare con precisione. Cicla con un conteggio intero e calcola il valore dentro il corpo, oppure usa < invece di !=.

Prossimo: Cicli while

Il ciclo for dà il meglio quando conosci il numero di ripetizioni in anticipo. Ma a volte devi ripetere finché una condizione non cambia, come leggere l'input fino alla fine del file o riprovare finché non va a buon fine, senza un numero fisso di passi. È il compito del ciclo while, che riduce l'intestazione a una sola condizione. Ne parliamo nella prossima pagina.

Domande frequenti

Come si scrive un ciclo for in C++?

Metti nell'intestazione tre parti separate da punto e virgola: un'inizializzazione, una condizione e un aggiornamento. for (int i = 0; i < 5; i++) { cout << i; } esegue il corpo con i che vale 0, 1, 2, 3, 4. Il ciclo si ferma non appena la condizione diventa false.

Qual è la differenza tra un ciclo for e un ciclo for basato su range in C++?

Un for classico ti dà un contatore di indice che controlli tu (for (int i = 0; i < n; i++)), utile quando ti serve la posizione o vuoi avanzare in modo personalizzato. Un for basato su range (for (int x : v)) nasconde l'indice e ti passa semplicemente ogni elemento: più pulito quando ti servono solo i valori.

Perché il mio ciclo for in C++ viene eseguito una volta di troppo o una volta in meno?

È il classico errore di uno (off-by-one). Usare <= invece di < con una dimensione che parte da zero esegue un'iterazione in più e legge oltre la fine dell'array; usare < quando volevi includere l'ultimo valore ne esegue una in meno. Per un array di dimensione n, lo schema sicuro è for (int i = 0; i < n; i++).

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA