Menu

If else in C: sintassi, esempi ed errori comuni

Come decide il C: l'istruzione if, else, le catene di else if, l'annidamento e l'operatore ternario, più la regola della verità (0 è falso, tutto il resto è vero) e il bug = contro == che rompe le condizioni in silenzio.

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

Perché i programmi hanno bisogno di diramazioni

Tutti i programmi visti finora sono andati dritti: riga 1, riga 2, riga 3. I programmi reali prendono decisioni. La password è corretta? Il numero è negativo? Il file si è aperto? L'istruzione if è il modo in cui il C fa una domanda ed esegue del codice solo quando la risposta è sì.

La condizione temperature > 30 viene valutata una volta. È vera, quindi il messaggio viene stampato. L'ultima riga sta fuori dalle graffe, quindi viene stampata in ogni caso. Cambia 31 in 18 ed eseguilo di nuovo: il primo messaggio sparisce e il secondo resta.

Sintassi: parentesi, graffe e niente punto e virgola

Un if in C ha una forma fissa:

if (condizione) {
    // eseguito quando la condizione e' diversa da zero
}

Tre regole da imparare presto. Le parentesi attorno alla condizione sono obbligatorie. Non esiste la parola chiave then. E non c'è punto e virgola dopo la parentesi di chiusura: uno messo per sbaglio chiude l'istruzione proprio lì:

// BUG: l'if non fa niente; la printf viene eseguita sempre
if (x > 10);
{
    printf("grande\n");
}

Compila senza problemi. Il ; è un'istruzione vuota che diventa il corpo dell'if, e le graffe sotto sono solo un blocco a sé che viene sempre eseguito. Compilare con gcc -Wall lo intercetta.

Le graffe in sé sono facoltative per una singola istruzione, ma lasciale. Un if senza graffe a cui più avanti si aggiunge una seconda riga è una fonte classica di bug, perché in C l'indentazione non raggruppa le istruzioni.

else ed else if

else fornisce l'altro percorso:

Per più di due esiti, concatena con else if. Il C controlla ogni condizione in ordine e si ferma alla prima vera:

Qui l'ordine conta moltissimo. Dato che la catena si ferma alla prima corrispondenza, il secondo test vede solo punteggi sotto 90, ed è per questo che score >= 80 non deve dire anche && score < 90. Scrivi la catena dalla condizione più restrittiva alla meno restrittiva, altrimenti ogni valore finisce nel primo ramo.

L'else finale è facoltativo. Mettilo ogni volta che la catena deve coprire tutti i casi; la sua assenza significa "se niente corrisponde, non fare nulla", il che va bene ma deve essere una scelta voluta.

La verità: 0 è falso, tutto il resto è vero

Il linguaggio C di base non ha un tipo booleano separato nelle condizioni. Un if chiede semplicemente se l'espressione è diversa da zero.

Le ultime due righe mostrano l'altra metà della regola: gli operatori di confronto sono espressioni normali che producono 1 per vero e 0 per falso. Ecco perché if (5 > 2) funziona: in realtà è if (1).

È anche il motivo per cui -3 è vero in C. La regola è diverso da zero, non positivo. Se vuoi sapere se un numero è positivo, scrivi if (n > 0), non if (n).

C99 ha aggiunto <stdbool.h> con un vero tipo bool più true e false, che nel codice nuovo si legge meglio. Sotto il cofano restano 1 e 0, quindi la regola qui sopra non cambia: vedi i booleani in C.

Gli operatori di confronto e logici che userai nelle condizioni:

==   uguale a                &&   AND logico (entrambi i lati veri)
!=   diverso da              ||   OR logico (almeno un lato vero)
<    minore di               !    NOT logico
>    maggiore di
<=   minore o uguale a
>=   maggiore o uguale a

&& e || sono a corto circuito: a && b non valuta mai b se a è falso, e a || b non valuta mai b se a è vero. È una garanzia, non un'ottimizzazione, quindi puoi scrivere tranquillamente if (n != 0 && total / n > 5): la divisione non può essere eseguita quando n vale zero.

Il bug = contro ==

È in assoluto l'errore più comune nelle condizioni in C:

// BUG: assegna 5 a x, poi valuta 5 (diverso da zero), quindi viene eseguito SEMPRE
if (x = 5) {
    printf("x vale cinque\n");
}

Il C permette l'assegnazione dentro un'espressione, quindi la riga è valida. Salva 5 in x, produce il valore 5, e 5 è diverso da zero: il ramo viene eseguito ogni singola volta, e x è stata sovrascritta in silenzio.

Due difese. Primo, compila sempre con gli avvisi attivi:

gcc -Wall -Wextra program.c -o program

GCC e clang segnalano entrambi "suggest parentheses around assignment used as truth value". Secondo, alcuni programmatori scrivono la costante prima della variabile, if (5 == x), così che un if (5 = x) scritto per sbaglio sia un errore di compilazione vero e non un bug silenzioso. Quello stile è questione di gusti; attivare gli avvisi no.

Annidamento

Un if può contenere un altro if. L'annidamento esprime condizioni che hanno senso solo quando una precedente è vera:

Due livelli si leggono bene. Quattro no. Quando l'annidamento si fa profondo, cerca un modo per appiattirlo: spesso combinando le condizioni con &&, oppure gestendo prima i casi di errore e uscendo subito:

// piu' piatto: gestisci le eccezioni, poi fai il lavoro
if (age < 18)     { printf("Solo per adulti.\n");                 return 0; }
if (!hasTicket)   { printf("Compra un biglietto, per favore.\n"); return 0; }
printf("Benvenuto.\n");

L'else pendente

Quando un if senza graffe è annidato dentro un altro, a quale if appartiene un else? La regola del C: un else si lega all'if senza else più vicino, indipendentemente da come è indentato il codice.

// L'else appartiene all'if INTERNO, nonostante l'indentazione
if (a > 0)
    if (b > 0)
        printf("entrambi positivi\n");
else
    printf("a non e' positivo\n");   // SBAGLIATO: eseguito quando a > 0 e b <= 0

L'indentazione dice che l'else va con l'if esterno. Il compilatore lo abbina a quello interno. Le graffe eliminano del tutto l'ambiguità, ed è questo il vero argomento per usarle sempre:

if (a > 0) {
    if (b > 0) {
        printf("entrambi positivi\n");
    }
} else {
    printf("a non e' positivo\n");
}

L'operatore ternario

Quando una diramazione esiste solo per scegliere un valore, l'operatore condizionale ? : lo dice in un'unica espressione:

Leggi cond ? x : y come "se cond allora x, altrimenti y". Viene valutato esattamente uno dei due rami, e l'insieme produce un valore, ed è per questo che si può assegnare o passare come argomento dove un'istruzione non potrebbe.

Tienilo per le scelte di valore semplici. I ternari annidati (a ? b : c ? d : e) sono validi e quasi sempre più difficili da leggere della catena di else if che sostituiscono.

Domande frequenti

Come si scrive un'istruzione if else in C?

Metti la condizione tra parentesi e il codice tra graffe: if (score >= 60) { printf("Pass\n"); } else { printf("Fail\n"); }. Il blocco else viene eseguito solo quando la condizione è falsa, e in C non esiste la parola chiave then.

Cosa conta come vero in un if in C?

Qualsiasi valore diverso da zero. Il C non ha un tipo booleano dedicato nella sua sintassi di base, quindi if (n) viene eseguito quando n vale qualsiasi cosa tranne 0, e if (!n) solo quando n vale esattamente 0. Gli operatori di confronto come == e < producono 1 per vero e 0 per falso.

Qual è la differenza tra = e == in C?

== confronta, = assegna. Scrivere if (x = 5) assegna 5 a x e poi valuta 5, che è diverso da zero, quindi il ramo viene eseguito sempre. Compila senza errori, ed è per questo che è il bug da principianti più comune nelle condizioni in C: la maggior parte dei compilatori lo segnala con -Wall.

Come funziona l'operatore ternario in C?

condition ? valueIfTrue : valueIfFalse è un'espressione che produce uno tra due valori, quindi può stare dentro un'assegnazione o come argomento di printf: int max = a > b ? a : b;. Usalo per scegliere un valore, e un normale if quando devi eseguire delle istruzioni.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA