venerdì 9 gennaio 2015

Modern C++ - I cicli e le condizioni

Ben ritrovati sulle pagine di Lubit - The Secrets of Ubuntu :-)
Nel post precedente abbiamo visto brevemente come definire una collezione dinamica, chiamata array, di elementi dello stesso tipo e come aggiungere/rimuovere elementi da essa.
Abbiamo anche visto come è possibile accedere agli elementi del vettore mediante un ciclo for. Oggi esamineremo piú nel dettaglio le possibili varianti di cicli esistenti in C++ e le condizioni per le quali è possibile iterare all'interno dei cicli.
Alla base delle condizioni e dei cicli esistono gli operatori di comparazione:
== uguale (identico)
<= minore o uguale
>= maggiore o uguale
< minore
> maggiore
!= diverso
E' possibile combinare tra loro piú operatori di comparazione mediante gli operatori logici:
! NOT restituisce true se l'operando è falso
&& AND restituisce true solo se gli operandi sono veri entrambi
|| OR restituisce true se almeno uno dei due operandi è vero

Le condizioni

Esistono 2 tipologie di condizioni: le condizioni basate su if e le condizioni basate su switch(case). Nel primo caso, si valuta se il risultato di una operazione assuma valore true oppure false (tipo di dato bool), mentre nel secondo caso si valuta il valore specificato nel case.
La sinossi per le condizioni basate su if è la seguente:
if(condizione)
{
   //operazioni
}
else
{
   //altre operazioni
}
dove per condizione ci riferiamo ad una operazione il cui risultato restituito è un valore booleano: true oppure false.
E' possibile scrivere piú condizioni if-else annidate. La regola generale è che il primo else si riferisce sempre all'ultimo if specificato.
La condizione del ramo else puó anche esser omessa, se non necessaria.

La sinossi per le condizioni basate su switch(case), invece, è la seguente:
switch(valore o variabile da valutare)
{
    case valore: operazione(); break;
    case 'valore'(se è un carattere): operazione2(); break;
    default: std::cout << "operazione non supportata" << std::endl;
}
Al termine di ogni caso (case) và specificata la parola chiave break, la quale permette di uscire dal blocco switch e ritornare ad eseguire il programma principale. Senza la parola break, verranno eseguite in cascata tutte le condizioni contenute all'interno del blocco switch. La parola chiave default invece permette di specificare un messaggio o una operazione da eseguire nel caso in cui una delle precedenti casistiche non sia verificata. Si noti che lo switch si sostituisce a blocchi if-else multipli.

Esempio:
int i{10}; //i = 10
if(i == 1) //i è uguale a 1?
{
    std::cout << "La variabile i è 1" << std::endl;
}
else if(i == 2) //i è uguale a 2?
{
    std::cout << "La variabile i è 2" << std::endl;
}
else if(i == 10) //i è uguale a 10?
{
    std::cout << "La variabile i è 10" << std::endl;
}
else
{
    std::cout << "i contiene il valore " << i << std::endl;
 
switch(i) //valuto il contenuto di i:
{
   case 1:  std::cout << "i contiene valore 1" << std::endl; break;
   case 2:  std::cout << "i contiene valore 2" << std::endl; break;
   case 10: std::cout << "i contiene valore 10" << std::endl; break;
   default: std::cout << "i contiene il valore " << i << std::endl;
}
 
In alternativa al classico blocco if-else, è possibile anche scrivere la forma contratta (condizione) ? operazione_se_true() : operazione_se_false();
Esempio:
i == 10 ? cout << "i vale 10" : cout << "i non vale 10";

I Cicli

Esistono 3 tipi di cicli: i cicli for, i cicli while e i cicli do-while.

For
Come abbiamo giá visto nel post precedente, un ciclo for ha la seguente sinossi:
for(valore_iniziale; condizione_finale; incremento)
{
   //operazioni;
}
oppure, in Modern C++, per vettori o container di elementi:
for(elemento:array)
{
   //operazioni;
}
Il ciclo for viene eseguito solo se la condizione finale è true. Non appena essa diventa false, il ciclo for viene interrotto. E' possibile inoltre forzare l'interruzione del ciclo mediante la parola chiave break, la quale permette di concludere il blocco-for immediatamente. Nel caso in cui, invece, si voglia saltare all'iterazione successiva (incrementando lo step), occorre usare la parola chiave continue.
Esempio:
std::vector<int> vettore(10, 10); //10 elementi, di valore 10
int somma = 0;
for(int i = 0; i < vettore.size(); ++i) //per i = 0, se i < 10 esegui operazioni
{
   if(vettore.at(i) == 0)   //se l'elemento i-esimo è 0, salta all'elemento ++i (i = i +1)
       continue;
   if(vettore.at(i) < 0)    //se l'elemento i-esimo è minore di 0, termina il ciclo
       break;

   somma = somma + vettore.at(i); //aggiungi l'elemento i-esimo alla somma
} //al termine di ogni ciclo, la variabile i è incrementata di 1 (++i)

While
In alternativa al ciclo for, si puó utilizzare il ciclo while, che viene eseguito fintanto che una condizione sia vera. Si pensi, ad esempio, ad un valore di soglia da raggiungere prima di interrompere le iterazioni.
La sinossi è la seguente:
while(condizione)
{
   //operazione
}

Do-While
In contrasto al ciclo while, il do-while viene eseguito almeno una volta, prima di verificarne la condizione di uscita.
La sinossi è la seguente: 
do
{
   //operazione
}while(condizione);
Vediamo nel dettaglio un breve esercizio/esempio:
int i{10}; //i = 10
while(i < 10)
{
    std::cout << i << std::endl;
    i++; //equivale a scrivere: i = i+1
}

do
{
    std::cout << i << std::endl;
    i++; //equivale a scrivere: i = i+1
}
while(i < 10);
Qual è il risultato dell'esempio precedente? Scrivete nei commenti il risultato è il perchè della risposta :)

Bonus:
E' possibile eseguire i cicli all'infinito (sconsigliatissimo) nel seguente modo:
for(;;)
{
   //operazioni
}

while(true)
{
   //operazioni
}

Alla prossima!

Nessun commento:

Posta un commento