C Language
Dichiarazioni di selezione
Ricerca…
if () Dichiarazioni
Uno dei modi più semplici per controllare il flusso del programma è quello di utilizzare if
istruzioni di selezione. Questa affermazione può decidere se un blocco di codice deve essere eseguito o non eseguito.
La sintassi per if
dichiarazione selezione in C potrebbe essere la seguente:
if(cond)
{
statement(s); /*to be executed, on condition being true*/
}
Per esempio,
if (a > 1) {
puts("a is larger than 1");
}
Dove a > 1
è una condizione che deve essere valutata a true
per eseguire le istruzioni all'interno del blocco if
. In questo esempio "a è maggiore di 1" viene stampato solo se a > 1
è vero.
if
istruzioni di selezione possono tralasciare le parentesi graffe {
e }
se c'è una sola affermazione all'interno del blocco. L'esempio sopra può essere riscritto a
if (a > 1)
puts("a is larger than 1");
Tuttavia, per eseguire più istruzioni all'interno di un blocco, le parentesi devono essere utilizzate.
La condizione per if
può includere più espressioni. if
eseguirà l'azione solo se il risultato finale dell'espressione è vero.
Per esempio
if ((a > 1) && (b > 1)) {
puts("a is larger than 1");
a++;
}
eseguirà solo printf
e a++
se sia a
che b
sono maggiori di 1
.
if () ... else istruzioni e sintassi
Mentre if
esegue un'azione solo quando la sua condizione viene valutata su true
, if
/ else
consente di specificare le diverse azioni quando la condizione è true
e quando la condizione è false
.
Esempio:
if (a > 1)
puts("a is larger than 1");
else
puts("a is not larger than 1");
Proprio come il if
dichiarazione, quando il blocco all'interno di if
o else
è composto da una sola istruzione, quindi le parentesi graffe può essere omessa (ma così facendo non è raccomandato in quanto può facilmente introdurre problemi involontariamente). Tuttavia, se c'è più di un'istruzione nel blocco if
o else
, le parentesi devono essere utilizzate su quel particolare blocco.
if (a > 1)
{
puts("a is larger than 1");
a--;
}
else
{
puts("a is not larger than 1");
a++;
}
switch () Dichiarazioni
switch
istruzioni switch
sono utili quando si desidera che il programma esegua molte cose diverse in base al valore di una particolare variabile di test.
Un esempio di utilizzo dell'istruzione switch
è simile a questo:
int a = 1;
switch (a) {
case 1:
puts("a is 1");
break;
case 2:
puts("a is 2");
break;
default:
puts("a is neither 1 nor 2");
break;
}
Questo esempio è equivalente a
int a = 1;
if (a == 1) {
puts("a is 1");
} else if (a == 2) {
puts("a is 2");
} else {
puts("a is neither 1 nor 2");
}
Se il valore di a
è 1 quando viene utilizzata l'istruzione switch
, verrà stampato a is 1
. Se il valore di a
è 2 allora, a is 2
verrà stampato. Altrimenti, a is neither 1 nor 2
verrà stampato a is neither 1 nor 2
.
case n:
è usato per descrivere dove salterà il flusso di esecuzione quando il valore passato all'istruzione switch
è n . n deve essere una costante in fase di compilazione e lo stesso n può esistere al massimo una volta in un'unica istruzione switch
.
default:
è usato per descrivere che quando il valore non corrisponde a nessuna delle scelte per il case n:
È buona norma includere un caso default
in ogni istruzione switch per rilevare comportamenti imprevisti.
Una break;
è richiesta una dichiarazione per saltare fuori dal blocco switch
.
Nota: se dimentichi accidentalmente di aggiungere break
dopo la fine di un case
, il compilatore presupporrà che intendi "fallire" e tutte le successive istruzioni caso, se presenti, verranno eseguite (a meno che non venga trovata un'istruzione break) uno qualsiasi dei casi successivi), indipendentemente dal fatto che le dichiarazioni dei casi susseguenti corrispondano o meno. Questa particolare proprietà viene utilizzata per implementare il dispositivo di Duff . Questo comportamento è spesso considerato un difetto nelle specifiche del linguaggio C.
Di seguito è riportato un esempio che mostra gli effetti dell'assenza di break;
:
int a = 1;
switch (a) {
case 1:
case 2:
puts("a is 1 or 2");
case 3:
puts("a is 1, 2 or 3");
break;
default:
puts("a is neither 1, 2 nor 3");
break;
}
Quando il valore di a
è 1 o 2, a is 1 or 2
e a is 1, 2 or 3
saranno entrambi stampati. Quando a
è 3, verrà stampato solo a is 1, 2 or 3
. Altrimenti, a is neither 1, 2 nor 3
stampato a is neither 1, 2 nor 3
.
Notare che il caso default
non è necessario, specialmente quando il set di valori che si ottiene nello switch
è finito e noto al momento della compilazione.
Il miglior esempio è usare un switch
su un enum
.
enum msg_type { ACK, PING, ERROR };
void f(enum msg_type t)
{
switch (t) {
case ACK:
// do nothing
break;
case PING:
// do something
break;
case ERROR:
// do something else
break;
}
}
Ci sono molti vantaggi nel fare questo:
- la maggior parte dei compilatori segnalerà un avviso se non si gestisce un valore (questo non verrebbe segnalato se fosse presente un caso
default
) - per lo stesso motivo, se aggiungi un nuovo valore
enum
, riceverai una notifica di tutti i luoghi in cui hai dimenticato di gestire il nuovo valore (con un casodefault
, avresti bisogno di esplorare manualmente il tuo codice alla ricerca di tali casi) - Il lettore non ha bisogno di capire "cosa è nascosto dal
default:
", se esistono altri valorienum
o se è una protezione per "just in case". E se ci sono altri valori dienum
, il programmatore ha intenzionalmente usato il casodefault
o c'è un bug che è stato introdotto quando ha aggiunto il valore? - la gestione di ogni valore
enum
rende il codice auto esplicativo in quanto non è possibile nascondersi dietro una wild card, è necessario gestirne esplicitamente ciascuno.
Tuttavia, non puoi impedire a qualcuno di scrivere codice malvagio come:
enum msg_type t = (enum msg_type)666; // I'm evil
Quindi puoi aggiungere un controllo extra prima del tuo passaggio per rilevarlo, se davvero ne hai bisogno.
void f(enum msg_type t)
{
if (!is_msg_type_valid(t)) {
// Handle this unlikely error
}
switch(t) {
// Same code than before
}
}
if () ... else Ladder Concatenare due o più if () ... else statements
Mentre l'istruzione if ()... else
consente di definire solo un comportamento (predefinito) che si verifica quando la condizione all'interno di if ()
non viene soddisfatta, concatenando due o più if () ... else
istruzioni consentono di definire una coppia più comportamenti prima di andare all'ultimo else
ramo che funge da "default", se presenti.
Esempio:
int a = ... /* initialise to some value. */
if (a >= 1)
{
printf("a is greater than or equals 1.\n");
}
else if (a == 0) //we already know that a is smaller than 1
{
printf("a equals 0.\n");
}
else /* a is smaller than 1 and not equals 0, hence: */
{
printf("a is negative.\n");
}
Nested if () ... else VS if () .. else Ladder
Nested if()...else
istruzioni richiedono più tempo di esecuzione (sono più lente) rispetto a if()...else
ladder perché le istruzioni nidificate if()...else
controllano tutte le istruzioni condizionali interne una volta che l'esterno l'istruzione condizionale if()
è soddisfatta, mentre if()..else
ladder interrompe il test di condizione una volta che una delle istruzioni condizionali if()
o else if()
sono vere.
An if()...else
ladder:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a, b, c;
printf("\nEnter Three numbers = ");
scanf("%d%d%d", &a, &b, &c);
if ((a < b) && (a < c))
{
printf("\na = %d is the smallest.", a);
}
else if ((b < a) && (b < c))
{
printf("\nb = %d is the smallest.", b);
}
else if ((c < a) && (c < b))
{
printf("\nc = %d is the smallest.", c);
}
else
{
printf("\nImprove your coding logic");
}
return 0;
}
È, nel caso generale, considerato migliore del nidificato equivalente if()...else
:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a, b, c;
printf("\nEnter Three numbers = ");
scanf("%d%d%d", &a, &b, &c);
if (a < b)
{
if (a < c)
{
printf("\na = %d is the smallest.", a);
}
else
{
printf("\nc = %d is the smallest.", c);
}
}
else
{
if(b < c)
{
printf("\nb = %d is the smallest.", b);
}
else
{
printf("\nc = %d is the smallest.", c);
}
}
return 0;
}