Vai al contenuto

Strutture di controllo

Condizioni e cicli per controllare il flusso di esecuzione del programma.

🖥️ In pratica con Windows Forms: Decisioni: if, else, switch e input sicuro e Ripetere e riutilizzare: cicli e metodi.

Cosa Imparerai in Questa Lezione

Le strutture di controllo sono il cuore della programmazione: permettono al tuo programma di prendere decisioni (if-else, switch) e ripetere azioni (for, while, foreach). Senza queste strutture, ogni programma sarebbe una semplice sequenza lineare di istruzioni.

Strutture Condizionali

Le strutture condizionali permettono di eseguire blocchi di codice solo se determinate condizioni sono vere. Sono come i bivi sulla strada: in base alla condizione, il programma sceglie quale strada seguire.

Istruzione if-else

  1. If base - Una sola condizione

Esegue il codice solo se la condizione è vera.

If Base

int età = 18;

if (età >= 18)
{
    Console.WriteLine("Sei maggiorenne");
}
// Se età < 18, non succede nulla
  1. If-else - Due alternative

Se la condizione è vera esegue il primo blocco, altrimenti il secondo.

If-Else

int età = 16;

if (età >= 18)
{
    Console.WriteLine("Sei maggiorenne");
}
else
{
    Console.WriteLine("Sei minorenne");  // Questo viene eseguito
}
  1. If-else if-else - Condizioni multiple

Verifica più condizioni in sequenza, esegue il primo blocco che è vero.

If-Else If-Else

int età = 15;

if (età < 13)
{
    Console.WriteLine("Sei un bambino");
}
else if (età < 18)
{
    Console.WriteLine("Sei un adolescente");  // Questo viene eseguito
}
else
{
    Console.WriteLine("Sei un adulto");
}

💡 Regole Importanti per if-else

  • La condizione deve sempre restituire un bool (true/false)
  • Le parentesi graffe {} sono opzionali per istruzioni singole, ma sempre consigliate
  • Solo il primo blocco che soddisfa la condizione viene eseguito
  • L'else è opzionale e cattura tutti i casi non gestiti

Operatore Ternario (?:)

Una forma compatta per assegnare valori basati su una condizione semplice. Sostituisce un if-else quando serve solo assegnare un valore.

Sintassi Operatore Ternario

// Sintassi: condizione ? valoreSeVero : valoreSeFalso

int età = 20;
string messaggio = età >= 18 ? "Maggiorenne" : "Minorenne";
Console.WriteLine(messaggio);  // "Maggiorenne"

// Equivalente a:
string messaggio;
if (età >= 18)
    messaggio = "Maggiorenne";
else
    messaggio = "Minorenne";

✅ Quando Usare il Ternario

Usa il ternario quando:

  • Devi assegnare un valore basato su una condizione semplice
  • La condizione e i valori sono brevi e chiari

Usa if-else quando:

  • Devi eseguire più istruzioni
  • La logica è complessa o annidata

Istruzione Switch

Lo switch è utile per confrontare una variabile con diversi valori possibili. È più leggibile di molti if-else quando si confronta la stessa variabile con molti valori.

Switch Tradizionale

int giornoSettimana = 3;

switch (giornoSettimana)
{
    case 1:
        Console.WriteLine("Lunedì");
        break;
    case 2:
        Console.WriteLine("Martedì");
        break;
    case 3:
        Console.WriteLine("Mercoledì");  // Questo viene eseguito
        break;
    case 4:
        Console.WriteLine("Giovedì");
        break;
    case 5:
        Console.WriteLine("Venerdì");
        break;
    case 6:
        Console.WriteLine("Sabato");
        break;
    case 7:
        Console.WriteLine("Domenica");
        break;
    default:
        Console.WriteLine("Giorno non valido");
        break;
}

⚠️ IMPORTANTE: Il break è obbligatorio!

Ogni case deve terminare con break (o return). Se manca, il programma non si compila (errore CS0163): a differenza di C, C++ e Java, in C# un case non può proseguire nel successivo (fall-through). Si può solo raggruppare più case vuoti sopra lo stesso blocco, come nell'esempio qui sotto.

Switch con Case Multipli

int giorno = 6;

switch (giorno)
{
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        Console.WriteLine("Giorno lavorativo");
        break;
    case 6:
    case 7:
        Console.WriteLine("Fine settimana");  // Questo viene eseguito
        break;
    default:
        Console.WriteLine("Giorno non valido");
        break;
}

🆕 Switch Expression (C# 8.0+)

Dalla versione 8.0, C# introduce una sintassi più compatta e funzionale per gli switch, che restituisce direttamente un valore.

Switch Expression Moderno

int giornoSettimana = 3;

string nomeGiorno = giornoSettimana switch
{
    1 => "Lunedì",
    2 => "Martedì",
    3 => "Mercoledì",      // Questo viene restituito
    4 => "Giovedì",
    5 => "Venerdì",
    6 => "Sabato",
    7 => "Domenica",
    _ => "Giorno non valido"  // _ è il default
};

Console.WriteLine(nomeGiorno);  // "Mercoledì"

Vantaggi: Più conciso, no break necessari, assegnazione diretta, più funzionale (restituisce un valore).

Cicli (Loops)

I cicli permettono di eseguire ripetutamente un blocco di codice finché una condizione è vera. Sono fondamentali per evitare di scrivere codice ripetitivo.

Ciclo for

Il ciclo for è utile quando conosci esattamente quante volte vuoi ripetere un'azione. Ha tre parti: inizializzazione, condizione e incremento.

Sintassi for

// Sintassi: for (inizializzazione; condizione; incremento)
//           {
//               corpo del ciclo
//           }

// Stampa i numeri da 1 a 10
for (int i = 1; i <= 10; i++)
{
    Console.WriteLine(i);
}

// Spiegazione:
// 1. int i = 1        → inizializza i a 1 (solo la prima volta)
// 2. i <= 10          → controlla se continuare (ogni iterazione)
// 3. i++              → incrementa i (dopo ogni iterazione)
// 4. Console.WriteLine(i) → esegue il corpo
  1. For con Array

Perfetto per iterare su array usando gli indici.

For con Array

int[] numeri = { 10, 20, 30, 40, 50 };

for (int i = 0; i < numeri.Length; i++)
{
    Console.WriteLine($"Elemento {i}: {numeri[i]}");
}

// Output:
// Elemento 0: 10
// Elemento 1: 20
// Elemento 2: 30
// ...
  1. For Inverso

Puoi iterare all'indietro cambiando l'incremento.

For al Contrario

// Countdown da 10 a 1
for (int i = 10; i >= 1; i--)
{
    Console.WriteLine(i);
}
Console.WriteLine("Via!");

Ciclo while

Il ciclo while esegue il blocco finché la condizione è vera. Utile quando non sai in anticipo quante iterazioni servono.

While Base

int contatore = 0;

while (contatore < 5)
{
    Console.WriteLine($"Contatore: {contatore}");
    contatore++;  // ⚠️ NON dimenticare di incrementare!
}

// Output:
// Contatore: 0
// Contatore: 1
// Contatore: 2
// Contatore: 3
// Contatore: 4

⚠️ ATTENZIONE: Cicli Infiniti!

Se dimentichi di modificare la variabile di controllo, il ciclo non terminerà mai!

// ❌ ERRORE: Ciclo infinito!
int x = 0;
while (x < 5)
{
    Console.WriteLine(x);
    // Manca x++! Il ciclo non finirà mai!
}

// ✅ CORRETTO
int x = 0;
while (x < 5)
{
    Console.WriteLine(x);
    x++;  // Incremento necessario
}

Ciclo do-while

Simile al while, ma garantisce almeno un'esecuzione del corpo. La condizione viene controllata alla fine, non all'inizio.

Do-While - Input Validato

int numero;

do
{
    Console.Write("Inserisci un numero maggiore di 10: ");
    string input = Console.ReadLine();
    int.TryParse(input, out numero);

} while (numero <= 10);  // Ripete finché numero <= 10

Console.WriteLine($"Hai inserito: {numero}");

📊 while vs do-while

while

  • Controlla PRIMA di eseguire
  • Può eseguire 0 volte
  • Usa quando: la condizione deve essere vera da subito

do-while

  • Esegue PRIMA di controllare
  • Esegue almeno 1 volta
  • Usa quando: serve almeno un'esecuzione (es. menu, input)

Ciclo foreach

Il ciclo foreach itera su collezioni (array, liste) senza gestire manualmente gli indici. È più semplice e sicuro del for quando non serve l'indice.

Foreach con Array

string[] città = { "Roma", "Milano", "Napoli", "Torino" };

foreach (string città in città)
{
    Console.WriteLine($"Città: {città}");
}

// Output:
// Città: Roma
// Città: Milano
// Città: Napoli
// Città: Torino

Foreach con List

List<int> numeri = new List<int> { 10, 20, 30, 40, 50 };

foreach (int numero in numeri)
{
    Console.WriteLine($"Numero: {numero}");
}

🔄 for vs foreach - Quando Usarli

Usa for quando:

  • Serve l'indice corrente
  • Devi modificare gli elementi
  • Iteri all'indietro
  • Devi saltare elementi

Usa foreach quando:

  • Serve solo leggere i valori
  • Non serve l'indice
  • Codice più pulito e leggibile
  • Meno probabilità di errori

Istruzioni di Controllo del Flusso

Queste istruzioni permettono di modificare il normale flusso di esecuzione dei cicli e dei metodi.

  1. break - Esce dal Ciclo

Termina immediatamente il ciclo più interno e continua dopo di esso.

Esempio break

// Cerca il primo numero maggiore di 15
int[] numeri = { 5, 10, 18, 22, 8 };

for (int i = 0; i < numeri.Length; i++)
{
    if (numeri[i] > 15)
    {
        Console.WriteLine($"Trovato: {numeri[i]}");
        break;  // Esce dal ciclo immediatamente
    }
}

// Output: Trovato: 18
// Il ciclo si ferma, non controlla 22 e 8
  1. continue - Salta all'Iterazione Successiva

Salta il resto del codice nel ciclo e passa alla prossima iterazione.

Esempio continue

// Stampa solo i numeri dispari
for (int i = 1; i <= 10; i++)
{
    if (i % 2 == 0)
    {
        continue;  // Salta i numeri pari
    }
    Console.WriteLine(i);
}

// Output: 1, 3, 5, 7, 9
// I numeri pari vengono saltati
  1. return - Termina il Metodo

Esce dal metodo corrente e (opzionalmente) restituisce un valore.

Esempio return

// Metodo che somma due numeri
int Somma(int a, int b)
{
    return a + b;  // Termina il metodo e restituisce il risultato
}

// Metodo che cerca un elemento
bool ContieneValore(int[] array, int valore)
{
    foreach (int elemento in array)
    {
        if (elemento == valore)
        {
            return true;  // Esce immediatamente se trovato
        }
    }
    return false;  // Se arriva qui, non è stato trovato
}

📊 Confronto break, continue, return

Istruzione Cosa fa Dove si usa
break Esce dal ciclo/switch corrente Cicli (for, while, foreach) e switch
continue Salta alla prossima iterazione Solo nei cicli
return Esce dal metodo (opzionalmente con valore) Qualsiasi metodo

Esempio Completo: Sistema di Classificazione

Vediamo un programma completo che utilizza tutte le strutture di controllo apprese per creare un sistema interattivo.

Program.cs - Sistema Completo

using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("=== SISTEMA DI CLASSIFICAZIONE ETÀ ===\n");

        // INPUT CON VALIDAZIONE (do-while)
        int età;
        do
        {
            Console.Write("Inserisci la tua età (0-120): ");
            string input = Console.ReadLine();

            if (!int.TryParse(input, out età))
            {
                Console.WriteLine("Input non valido! Inserisci un numero.");
                età = -1;  // Forza ripetizione
            }
            else if (età < 0 || età > 120)
            {
                Console.WriteLine("Età non valida! Deve essere tra 0 e 120.");
            }

        } while (età < 0 || età > 120);

        // CLASSIFICAZIONE CON IF-ELSE IF
        string categoria;
        if (età < 3)
        {
            categoria = "Neonato";
        }
        else if (età < 13)
        {
            categoria = "Bambino";
        }
        else if (età < 18)
        {
            categoria = "Adolescente";
        }
        else if (età < 65)
        {
            categoria = "Adulto";
        }
        else
        {
            categoria = "Anziano";
        }

        Console.WriteLine($"\nCategoria: {categoria}");

        // SWITCH PER GIORNO DELLA SETTIMANA
        Console.Write("\nInserisci giorno (1-7) per info settimana: ");
        if (int.TryParse(Console.ReadLine(), out int giorno))
        {
            // Switch expression moderno
            string tipoGiorno = giorno switch
            {
                >= 1 and <= 5 => "Giorno lavorativo",
                6 or 7 => "Fine settimana",
                _ => "Giorno non valido"
            };

            Console.WriteLine($"Tipo: {tipoGiorno}");
        }

        // CICLO FOR - Tabellina
        Console.Write("\nVuoi vedere una tabellina? (s/n): ");
        if (Console.ReadLine()?.ToLower() == "s")
        {
            Console.Write("Quale tabellina (1-10)? ");
            if (int.TryParse(Console.ReadLine(), out int numero))
            {
                Console.WriteLine($"\nTabellina del {numero}:");
                for (int i = 1; i <= 10; i++)
                {
                    Console.WriteLine($"{numero} x {i} = {numero * i}");
                }
            }
        }

        // CICLO WHILE - Conta alla rovescia
        Console.Write("\nVuoi un countdown? (s/n): ");
        if (Console.ReadLine()?.ToLower() == "s")
        {
            int contatore = 5;
            while (contatore > 0)
            {
                Console.WriteLine(contatore);
                System.Threading.Thread.Sleep(1000);  // Pausa 1 secondo
                contatore--;
            }
            Console.WriteLine("Via!");
        }

        // FOREACH - Lista nomi
        string[] nomiCategorie = { "Neonato", "Bambino", "Adolescente", "Adulto", "Anziano" };
        Console.WriteLine("\n=== Categorie Disponibili ===");
        foreach (string nome in nomiCategorie)
        {
            Console.WriteLine($"- {nome}");
        }

        // BREAK E CONTINUE - Ricerca
        Console.WriteLine("\n=== Ricerca Numeri Pari ===");
        int[] numeri = { 1, 4, 7, 8, 10, 11, 14, 15 };
        int contaPari = 0;

        foreach (int num in numeri)
        {
            if (num % 2 != 0)
            {
                continue;  // Salta i dispari
            }

            Console.WriteLine($"Trovato numero pari: {num}");
            contaPari++;

            if (contaPari >= 3)
            {
                Console.WriteLine("Raggiunti 3 numeri pari, stop.");
                break;  // Esce dopo 3 pari
            }
        }

        Console.WriteLine($"\nTotale numeri pari trovati: {contaPari}");
        Console.WriteLine("\n=== FINE PROGRAMMA ===");
    }
}

💡 Analisi del Codice

  • do-while - Validazione input (almeno 1 esecuzione garantita)
  • if-else if - Classificazione età in categorie
  • switch expression - Tipo giorno (sintassi moderna C# 9)
  • for - Tabellina (numero fisso di iterazioni)
  • while - Countdown (condizione valutata prima)
  • foreach - Iterazione su array senza indici
  • continue - Salta numeri dispari
  • break - Esce dopo 3 numeri pari trovati

Esercizi Pratici

Esercizio 1: Calcolatore di Media Voti

Crea un programma che:

  • Chiede quanti voti inserire (validazione con do-while)
  • Usa un ciclo for per inserire i voti
  • Salta i voti non validi (continue)
  • Calcola e mostra la media
  • Determina il giudizio con if-else o switch expression
Mostra la soluzione

Soluzione Esercizio 1

using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("=== CALCOLATORE MEDIA VOTI ===\n");

        // Input numero voti con validazione
        int numeroVoti;
        do
        {
            Console.Write("Quanti voti vuoi inserire (1-20)? ");
            string input = Console.ReadLine();

            if (!int.TryParse(input, out numeroVoti) || numeroVoti < 1 || numeroVoti > 20)
            {
                Console.WriteLine("Numero non valido!");
                numeroVoti = 0;
            }
        } while (numeroVoti < 1 || numeroVoti > 20);

        // Inserimento voti
        double somma = 0;
        int votiValidi = 0;

        for (int i = 1; i <= numeroVoti; i++)
        {
            Console.Write($"Voto {i} (18-30): ");

            if (!int.TryParse(Console.ReadLine(), out int voto))
            {
                Console.WriteLine("Input non valido, saltato.");
                continue;  // Salta questo voto
            }

            if (voto < 18 || voto > 30)
            {
                Console.WriteLine("Voto non valido (18-30), saltato.");
                continue;  // Salta voti fuori range
            }

            somma += voto;
            votiValidi++;
        }

        // Calcolo media
        if (votiValidi == 0)
        {
            Console.WriteLine("\nNessun voto valido inserito!");
            return;
        }

        double media = somma / votiValidi;
        Console.WriteLine($"\nMedia: {media:F2} ({votiValidi}/{numeroVoti} voti validi)");

        // Giudizio con switch expression
        string giudizio = media switch
        {
            >= 28 => "Eccellente",
            >= 24 => "Buono",
            >= 21 => "Discreto",
            >= 18 => "Sufficiente",
            _ => "Non classificato"
        };

        Console.WriteLine($"Giudizio: {giudizio}");
    }
}

Esercizio 2: Gioco Indovina il Numero

Crea un gioco in cui:

  • Il computer sceglie un numero casuale (1-100)
  • L'utente ha massimo 7 tentativi (for o while)
  • Dai suggerimenti "troppo alto" o "troppo basso"
  • Esci con break se indovina
  • Mostra messaggi di vittoria/sconfitta
Mostra la soluzione

Soluzione Esercizio 2

using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("=== INDOVINA IL NUMERO ===\n");
        Console.WriteLine("Ho pensato un numero tra 1 e 100.");
        Console.WriteLine("Hai 7 tentativi!\n");

        Random random = new Random();
        int numeroSegreto = random.Next(1, 101);  // 1-100
        int tentativiMax = 7;
        bool indovinato = false;

        for (int tentativo = 1; tentativo <= tentativiMax; tentativo++)
        {
            Console.Write($"Tentativo {tentativo}/{tentativiMax}: ");

            if (!int.TryParse(Console.ReadLine(), out int numeroUtente))
            {
                Console.WriteLine("Input non valido!");
                continue;  // Non conta come tentativo
            }

            if (numeroUtente < 1 || numeroUtente > 100)
            {
                Console.WriteLine("Numero fuori range (1-100)!");
                continue;
            }

            // Controllo
            if (numeroUtente == numeroSegreto)
            {
                Console.WriteLine($"\n🎉 COMPLIMENTI! Hai indovinato in {tentativo} tentativi!");
                indovinato = true;
                break;  // Esce dal ciclo
            }
            else if (numeroUtente < numeroSegreto)
            {
                Console.WriteLine("📈 Troppo basso! Prova con un numero più alto.");
            }
            else
            {
                Console.WriteLine("📉 Troppo alto! Prova con un numero più basso.");
            }

            // Suggerimento finale
            if (tentativo == tentativiMax - 1)
            {
                Console.WriteLine("\n⚠️ ULTIMO TENTATIVO!");
            }
        }

        if (!indovinato)
        {
            Console.WriteLine($"\n😞 GAME OVER! Il numero era: {numeroSegreto}");
        }
    }
}

🎯 Riepilogo Lezione

Condizioni:

  • if-else - Decisioni semplici
  • else if - Condizioni multiple
  • Operatore ternario - Assegnazioni veloci
  • switch - Confronti multipli
  • switch expression - Sintassi moderna

Cicli:

  • for - Iterazioni fisse
  • while - Condizione prima
  • do-while - Almeno 1 esecuzione
  • foreach - Collezioni semplici
  • break, continue, return - Controllo flusso