Il costrutto switch in C e C++
In molti problemi di programmazione ci troviamo di fronte a scelte multiple: in base al valore di una variabile, il programma deve eseguire azioni differenti.
Una soluzione è utilizzare una serie di if-else-if in cascata, ma questa può rendere il codice poco leggibile.
Per queste situazioni, in C e C++ si utilizza l’istruzione di selezione multipla switch.
Sintassi generale
switch (espressione) {
case valore1:
// istruzioni
break;
case valore2:
// istruzioni
break;
...
default:
// istruzioni di default
}
Osservazioni
- L’espressione può restituire solo valori interi o carattere.
- Ogni
casedeve avere una costante intera ocharunivoca. - Ogni ramo termina tipicamente con
breakper evitare il fall-through (esecuzione dei case successivi). - Il blocco
defaultè opzionale, eseguito quando non c’è alcuna corrispondenza.
Esempio 1 – Menù bancomat
#include <iostream>
using namespace std;
void prelievo(){ cout << "Hai scelto il prelievo.\n"; }
void lista(){ cout << "Hai scelto la lista movimenti.\n"; }
void saldo(){ cout << "Hai scelto il saldo.\n"; }
int main() {
char ch;
cout << "1. Prelievo\n";
cout << "2. Lista movimenti\n";
cout << "3. Saldo\n";
cin >> ch;
switch(ch) {
case '1': prelievo(); break;
case '2': lista(); break;
case '3': saldo(); break;
default: cout << "Nessuna opzione selezionata\n";
}
return 0;
}
Esempio 2 – Giorno della settimana
#include <iostream>
using namespace std;
int main() {
int giorno;
cout << "Inserisci un numero (1..7): ";
cin >> giorno;
switch(giorno) {
case 1: cout << "Lunedi'" << endl; break;
case 2: cout << "Martedi'" << endl; break;
case 3: cout << "Mercoledi'" << endl; break;
case 4: cout << "Giovedi'" << endl; break;
case 5: cout << "Venerdi'" << endl; break;
case 6: cout << "Sabato" << endl; break;
case 7: cout << "Domenica" << endl; break;
default: cout << "Valore non valido" << endl;
}
return 0;
}
Uso del fall-through
Una volta acquisito il valore intero della variabile giorno, il controllo passa al case corrispondente.
Se, ad esempio, inseriamo il valore 4 e non mettiamo break, vengono eseguite anche le istruzioni dei case successivi (5, 6, 7, e anche default se presente).
Questo comportamento si chiama fall-through. Per limitarlo ai soli casi desiderati, si utilizza break in chiusura di ciascun ramo.
È anche possibile far confluire più case nello stesso blocco di istruzioni.
Attenzione: il fall-through (mancanza di break) è spesso un errore, ma a volte è voluto. Ecco quando può essere utile:
- Raggruppare più
caseche condividono le stesse istruzioni (es.: mesi da 30 giorni). - Applicare logiche a “livelli” dove i casi successivi ereditano parte del comportamento dei precedenti.
- Mappare categorie affini (es.: vocali vs consonanti) evitando duplicazioni.
Esempio (raggruppamento corretto):
switch(mese) {
case 4: case 6: case 9: case 11:
giorni = 30;
break;
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
giorni = 31;
break;
case 2:
// logica febbraio...
break;
default:
// non valido
}
Esempio (fall-through intenzionale, segnalato):
switch(livello) {
case 3:
bonus += 30;
[[fallthrough]]; // C++17: indica che il fall-through è voluto
case 2:
bonus += 20;
/* fallthrough */ // C / GCC/Clang: commento esplicito
case 1:
bonus += 10;
break;
default:
bonus = 0;
}
Common pitfalls:
- Dimenticare
breakquando non si intende il fall-through. - Valori duplicati nei
case(non ammessi nello stessoswitch). - Usare espressioni non costanti nei
case(servono costanti note a compile-time). - Stringhe nei
case(non supportate in C/C++; usareif-else-ifo mappe).
Esempio 3 – Giorni del mese
#include <iostream>
using namespace std;
int main() {
int mese, anno, giorniMese;
cout << "Inserisci mese (1..12) e anno: ";
cin >> mese >> anno;
switch(mese) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
giorniMese = 31; break;
case 4: case 6: case 9: case 11:
giorniMese = 30; break;
case 2:
if ( (anno % 4 == 0 && anno % 100 != 0) || (anno % 400 == 0) )
giorniMese = 29;
else
giorniMese = 28;
break;
default:
cout << "Mese non valido" << endl;
return 0;
}
cout << "Il mese ha " << giorniMese << " giorni." << endl;
return 0;
}
switch(n) {
case 1:
case 2:
cout << "n vale 1 oppure 2\n";
break;
case 3:
cout << "n vale 3\n";
break;
}
Esercizi
Esercizio 1 – Completa il codice
switch(myVar) {
case 1:
case 2:
cout << "myVar e' uguale a _______ ";
break;
case 3:
cout << "myVar e' uguale a _______ ";
break;
case 4:
cout << "myVar e' uguale a _______ ";
break;
}
Esercizio 2 – Programma incompleto
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Inserisci un numero intero: ";
cin >> n;
switch(n) {
case 1:
cout << "Hai inserito il numero _______";
break;
case 0:
cout << "Hai inserito il numero _______";
break;
// aggiungi altri case, se necessario
default:
cout << "Valore non gestito";
}
return 0;
}
Esercizio 3 – Mesi
Scrivi un programma che, dato un numero da 1 a 12, visualizzi il mese corrispondente (es. 1 → Gennaio, 2 → Febbraio, …).
Confronto: switch vs if-else-if
| Caratteristica | switch | if-else-if |
|---|---|---|
| Tipi di confronto | Solo uguaglianza con costanti intere o char | Qualsiasi condizione logica (>, <, ==, &&, ||, …) |
| Leggibilità | Più compatto e chiaro per scelte multiple | Diventa poco leggibile con molte condizioni |
| Fall-through | Presente di default (serve break) | Non esiste: ogni ramo è indipendente |
| Flessibilità | Limitato a costanti note a compile-time | Può usare variabili, espressioni e funzioni complesse |
| Uso tipico | Menù, mapping numeri → etichette, giorni, mesi… | Decisioni basate su condizioni logiche articolate |
| Efficienza | Spesso più efficiente: il compilatore può ottimizzare con jump table | Generalmente meno efficiente se le condizioni sono numerose |
In sintesi: switch è ideale per scelte multiple semplici e leggibili, mentre if-else-if rimane insostituibile quando occorrono condizioni complesse o confronti non basati su uguaglianze.
Ora tocca a te – Esercizi
Esercizio 1 – Completa il codice
switch(myVar) {
case 1:
case 2:
cout << "myVar e' uguale a _______ ";
break;
case 3:
cout << "myVar e' uguale a _______ ";
break;
case 4:
cout << "myVar e' uguale a _______ ";
break;
}
Esercizio 2 – Programma incompleto
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Inserisci un numero intero: ";
cin >> n;
switch(n) {
case 1:
cout << "Hai inserito il numero _______";
break;
case 0:
cout << "Hai inserito il numero _______";
break;
// aggiungi altri case a piacere
}
return 0;
}
Esercizio 3 – Giorni della settimana
Scrivi un programma che, dato un numero da 1 a 7, visualizzi il giorno della settimana corrispondente (1 → Lunedì, …, 7 → Domenica).
Usa switch e il blocco default per i valori non validi.
Esercizio 4 – Menù calcolatrice
Realizza un menù testuale che offra all’utente 4 scelte:
1. Somma 2. Differenza 3. Prodotto 4. Divisione
Leggi due numeri e, in base alla scelta, esegui l’operazione corrispondente. Se l’utente inserisce un’opzione non valida, mostra un messaggio di errore.
Esercizio 5 – Vocale o consonante (fall-through)
Scrivi un programma che, dato un carattere alfabetico, determini se è vocale o consonante.
Usa uno switch con più case in sequenza per gestire le vocali (a, e, i, o, u in maiuscolo e minuscolo).
Sfrutta il fall-through per raggruppare più casi nello stesso blocco di istruzioni.
Soluzioni
Soluzione Esercizio 1 – Completa il codice
Le tre righe mancanti sono i valori visualizzati (1, 3, 4) coerenti con i rami case.
switch(myVar) {
case 1:
case 2:
cout << "myVar e' uguale a 1 oppure 2";
break;
case 3:
cout << "myVar e' uguale a 3";
break;
case 4:
cout << "myVar e' uguale a 4";
break;
}
Soluzione Esercizio 2 – Programma incompleto
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Inserisci un numero intero: ";
cin >> n;
switch(n) {
case 1:
cout << "Hai inserito il numero 1";
break;
case 0:
cout << "Hai inserito il numero 0";
break;
default:
cout << "Valore non gestito";
}
return 0;
}
Soluzione Esercizio 3 – Giorni della settimana
#include <iostream>
using namespace std;
int main() {
int giorno;
cout << "Inserisci un numero (1..7): ";
cin >> giorno;
switch(giorno) {
case 1: cout << "Lunedi'"; break;
case 2: cout << "Martedi'"; break;
case 3: cout << "Mercoledi'"; break;
case 4: cout << "Giovedi'"; break;
case 5: cout << "Venerdi'"; break;
case 6: cout << "Sabato"; break;
case 7: cout << "Domenica"; break;
default: cout << "Valore non valido";
}
cout << endl;
return 0;
}
Soluzione Esercizio 4 – Menù calcolatrice
#include <iostream>
using namespace std;
int main() {
cout << "1) Somma\n2) Differenza\n3) Prodotto\n4) Divisione\n";
cout << "Scegli opzione (1-4): ";
int scelta; cin >> scelta;
double a, b;
cout << "Inserisci due numeri: ";
cin >> a >> b;
switch(scelta) {
case 1:
cout << "Somma = " << (a + b);
break;
case 2:
cout << "Differenza = " << (a - b);
break;
case 3:
cout << "Prodotto = " << (a * b);
break;
case 4:
if (b == 0) cout << "Errore: divisione per zero!";
else cout << "Quoziente = " << (a / b);
break;
default:
cout << "Opzione non valida";
}
cout << endl;
return 0;
}
Soluzione Esercizio 5 – Vocale o consonante (fall-through)
#include <iostream>
#include <cctype> // tolower
using namespace std;
int main() {
char c;
cout << "Inserisci una lettera: ";
cin >> c;
char ch = tolower(static_cast<unsigned char>(c));
switch(ch) {
case 'a': case 'e': case 'i': case 'o': case 'u':
cout << c << " e' una vocale";
break;
default:
if ( (ch >= 'a' && ch <= 'z') ) cout << c << " e' una consonante";
else cout << c << " non e' una lettera";
}
cout << endl;
return 0;
}
Le vocali sono gestite con più case in sequenza (fall-through intenzionale).