Ciclo While in C#

Concetti Chiave
  • Il ciclo while esegue il suo corpo finché la condizione è vera.
  • L'istruzione break interrompe il ciclo in modo prematuro.
  • Il ciclo while può essere utilizzato per risolvere problemi come la somma di numeri o la verifica di numeri primi.
  • È importante evitare i cicli infiniti, che si verificano quando la condizione del ciclo non diventa mai falsa.

Il Ciclo while

Uno dei cicli più semplici e comunemente usati è il ciclo while.

La sua sintassi è la seguente:

while (condizione)
{
    // corpo del ciclo
    // codice da eseguire ad ogni iterazione
    // del ciclo
    // ...
}

Nell'esempio di codice sopra, condizione è una qualsiasi espressione che restituisce un risultato Boolean, ossia true o false. Essa determina per quanto tempo il corpo del ciclo verrà ripetuto ed è chiamata la condizione del ciclo. In questo esempio il corpo del ciclo è il codice di programmazione eseguito ad ogni iterazione del ciclo, cioè ogni volta che la condizione di input è true. Il comportamento dei cicli while può essere rappresentato dal seguente schema:

Diagramma di flusso del ciclo while
Figura 1: Diagramma di flusso del ciclo while

Nel ciclo while, prima di tutto viene calcolata l'espressione Boolean e se è true viene eseguita la sequenza di operazioni nel corpo del ciclo. Poi viene controllata di nuovo la condizione e se è di nuovo true viene eseguito il corpo del ciclo. Tutto questo viene ripetuto ancora e ancora finché ad un certo punto l'espressione condizionale restituisce il valore false. A questo punto il ciclo si ferma e il programma continua alla riga successiva, immediatamente dopo il corpo del ciclo.

Il corpo del ciclo while potrebbe non essere eseguito nemmeno una volta se all'inizio la condizione del ciclo restituisce false. Se la condizione del ciclo non viene mai interrotta il ciclo verrà eseguito indefinitamente. Si parla allora di ciclo infinito.

Utilizzo del ciclo while

Consideriamo un esempio molto semplice di utilizzo del ciclo while.

Lo scopo del ciclo di questo esempio è stampare sulla console i numeri nell'intervallo da 0 a 9 in ordine crescente:

// Inizializza il contatore
int contatore = 0;

// Esegui il corpo del ciclo mentre la condizione del ciclo è vera
while (contatore <= 9)
{
    // Stampa il valore del contatore
    Console.WriteLine("Numero : " + contatore);
    // Incrementa il contatore
    contatore++;
}

Console.WriteLine("Fine del ciclo");

Quando eseguiamo il codice di esempio otteniamo il seguente risultato:

Numero : 0
Numero : 1
Numero : 2
Numero : 3
Numero : 4
Numero : 5
Numero : 6
Numero : 7
Numero : 8
Numero : 9
Fine del ciclo

Diamo alcuni esempi aggiuntivi per illustrare l'utilità dei cicli e per mostrare alcuni problemi che possono essere risolti utilizzando i cicli.

Esempio 1: Somma dei numeri da 1 a N

In questo esempio esamineremo come utilizzando il ciclo while possiamo trovare la somma dei numeri da 1 a n. Il numero n viene letto dalla console:

Console.Write("Inserisci il numero n = ");
int n = int.Parse(Console.ReadLine());

int numero = 1;
int somma = 1;

Console.Write("La somma 1");

while (numero < n)
{
  numero++;
  somma += numero;
  Console.Write(" + " + numero);
}

Console.WriteLine(" = " + somma);

Prima inizializziamo le variabili numero e somma con il valore di 1. In numero manteniamo il numero corrente, che aggiungiamo alla somma dei numeri precedenti.

Attraverso ogni ciclo incrementiamo numero di 1 per ottenere il numero successivo, poi nella condizione del ciclo controlliamo se è nell'intervallo da 1 a n. La variabile somma contiene la somma dei numeri da 1 a numero in qualsiasi momento. Al momento di entrare nel ciclo aggiungiamo a somma il numero successivo memorizzato in numero. Stampiamo sulla console tutti i numeri numero da 1 a n con un separatore "+" e il risultato finale della somma dopo la fine del ciclo. Il risultato dell'esecuzione del programma è il seguente (inseriamo n = 15):

Inserisci il numero n = 15
La somma 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 = 120

Diamo un altro esempio di utilizzo del ciclo while, prima di passare ad altre strutture per organizzare i cicli.

Esempio 2: Verifica se un numero è primo

Scriveremo un programma per verificare se un numero dato è primo o no.

Leggeremo il numero da verificare dalla console. Come sappiamo dalla matematica, un numero primo è qualsiasi numero intero positivo che non è divisibile per altri numeri eccetto 1 e se stesso.

Possiamo verificare se il numero num è primo quando in un ciclo controlliamo se è divisibile per numeri da 2 a \sqrt{n}. Questo è il classico algoritmo di verifica dei numeri primi.

Console.Write("Inserisci un numero positivo: ");
int num = int.Parse(Console.ReadLine());

int divisore = 2;
int divisoreMassimo = (int) Math.Sqrt(num);

bool primo = true;

while (primo && (divisore <= divisoreMassimo))
{
    if (num % divisore == 0) {
        primo = false;
    }
    divisore++;
}

Console.WriteLine("Primo? " + primo);

Utilizziamo la variabile divisore per memorizzare il valore di un potenziale divisore del numero. Prima la inizializziamo con 2 (il divisore più piccolo possibile).

La variabile divisoreMassimo è il massimo divisore possibile, che è uguale alla radice quadrata del numero. Se abbiamo un divisore maggiore di \sqrt{n}, allora num dovrebbe avere anche un altro divisore minore di \sqrt{n} ed è per questo che è inutile controllare i numeri maggiori di \sqrt{n}. In questo modo riduciamo il numero di iterazioni del ciclo.

Per il risultato utilizziamo una variabile booleana chiamata primo. Inizialmente, il suo valore è true. Mentre si passa attraverso il ciclo, se risulta che il numero ha un divisore, il valore di primo diventerà false.

La condizione del ciclo while consiste di due altre sotto-condizioni che sono correlate all'operatore logico (logical and). Per eseguire il ciclo, queste due sotto-condizioni devono essere vere simultaneamente. Se a un certo punto troviamo un divisore del numero num, la variabile primo diventa false e la condizione del ciclo non è più soddisfatta. Questo significa che il ciclo viene eseguito finché non trova il primo divisore del numero o finché non dimostra il fatto che num non è divisibile per nessuno dei numeri nell'intervallo da 2 a \sqrt{n}.

Ecco come appare il risultato dell'esecuzione dell'esempio sopra se i valori di input sono rispettivamente i numeri 37 e 34:

Inserisci un numero positivo: 37
Primo? True
Inserisci un numero positivo: 34
Primo? False

Istruzione break

L'istruzione break viene utilizzata per uscire prematuramente dal ciclo, prima che abbia completato la sua esecuzione in modo naturale.

Quando il ciclo raggiunge l'istruzione break, viene terminato e l'esecuzione del programma continua dalla riga immediatamente dopo il corpo del ciclo. La terminazione di un ciclo con l'istruzione break può essere eseguita solo dal suo corpo, durante un'iterazione del ciclo. Quando break viene eseguito, il codice nel corpo del ciclo che lo segue viene saltato e non eseguito.

Dimostreremo l'uscita dal ciclo con break attraverso un esempio.

Esempio: Calcolo del Fattoriale

In questo esempio calcoleremo il fattoriale di un numero inserito dalla console. Il calcolo viene eseguito utilizzando un ciclo while infinito e l'istruzione break.

Ricordiamo dalla matematica cos'è il fattoriale e come viene calcolato. Il fattoriale di un numero intero n è una funzione che viene calcolata come prodotto di tutti i numeri interi minori o uguali a n. È scritto come n! e per definizione le seguenti formule sono valide per esso:

  • n! = 1 \cdot 2 \cdot 3 \cdot \ldots \cdot (n-1) \cdot n, per n &gt; 1;
  • 2! = 1 \cdot 2;
  • 1! = 1;
  • 0! = 1.

Il prodotto n! può essere espresso tramite un fattoriale di numeri interi minori di n:

  • n! = (n-1)! \cdot n, utilizzando il valore iniziale di 0! = 1.

Per calcolare il fattoriale di n utilizzeremo direttamente la definizione:

Console.Write("Inserisci un numero n = ");

// Leggiamo il numero n dalla console
int n = int.Parse(Console.ReadLine());

// "decimal" è il tipo più grande di C#
// che può contenere valori interi
decimal fattoriale = 1;

// Eseguiamo un "ciclo infinito"
while (true)
{
    if (n <= 1)
    {
        break;
    }

    // Moltiplichiamo il risultato corrente per n
    // e riduciamo n di 1
    // (n! = n * (n-1)!)
    fattoriale *= n;
    n--;
}

Console.WriteLine("n! = " + fattoriale);

Prima inizializziamo la variabile fattoriale con 1 e leggiamo n dalla console.

Costruiamo un ciclo while infinito utilizzando true come condizione del ciclo. Utilizziamo l'operatore break per terminare il ciclo quando n raggiunge un valore minore o uguale a 1.

Altrimenti, moltiplichiamo il risultato corrente per n e riduciamo n di un'unità.

Praticamente nella prima iterazione del ciclo la variabile fattoriale ha un valore n, nella seconda n\cdot(n-1) e così via. Nell'ultima iterazione del ciclo il valore di fattoriale è il prodotto:

n \cdot (n-1) \cdot(n-2) \cdot \ldots \cdot 3 \cdot 2 = n!

che è il valore desiderato di n!.

Se eseguiamo il programma di esempio e inseriamo 20 come input, otteniamo il seguente risultato:

Inserisci un numero n = 20
n! = 2432902008176640000