- Programmare in C++ (5 lezione) -
 
COSA SERVE PER QUESTO TUTORIAL
Download | Chiedi sul FORUM | Glossario Qualche conoscenza nell'ambito della programmazione semplice - conoscenze matematiche di base - un compilatore (Borland o Microsoft) - il codice sorgente della lezione.
Istruzioni del C++ atte ad eseguire azioni più volte fino al verificarsi di una condizione

LE ISTRUZIONI CICLICHE
Che cosa sono e a cosa servono i cicli in un programma C++

Le istruzioni cicliche permettono, come dice il nome stesso, l'esecuzione di una determinata serie di azioni in modo ciclico (ovvero dall'inizio alla fine più volte consecutivamente) fino al verificarsi di una o più condizione prestabilite (queste ultime sanciscono insomma la fine della ripetizione). Per comprendere l'utilità di questi importantissimi componenti del C++ passiamo ad un secondo esempio teorico:


//ESEMPIO TEORICO DI UN CICLO

//Immaginiamo di voler stampare banalmente
//su schermo tutti i numeri da 1 a 12

//Ecco quindi il nostro ciclo:

////// IMPOSTIAMO IL CICLO //// PARTE 1 ////////////////////////////////////////////////////////////////////
//SITUAZIONE DI PARTENZA: la variabile A è uguale a 1 -> SITUAZIONE INIZIALE DELLA VARIABILE-CONTATORE

//LIMITE: procedi fino a quando A è minore di 13 ------> LA CONDIZIONE CHE DEVE ESSERE VERIFICATA AFFINCHE'
//                                                       LE ISTRUZIONI INTERNE AL CICLO VENGANO ESEGUITE

//INCREMENTO: ad esempio A uguale ad A più 1 ----------> QUANTO AGGIUNGERE AL CONTATORE DOPO OGNI CICLO
////////////////////////////////////////////////////////////////////////////////////////////////////////////


////// ISTRUZIONI INTERNE AL CICLO //// PARTE 2 ////////////////////////////////////////////////////////////
//AZIONE: stampiamo su schermo il valore di A ---------> DA ESEGUIRE OGNI VOLTA CHE DOPO L'INCREMENTO
//                                                       LA CONDIZIONE-LIMITE E' VERIFICATA
////////////////////////////////////////////////////////////////////////////////////////////////////////////


////// FINE //// PARTE 3 ///////////////////////////////////////////////////////////////////////////////////
//FINE del ciclo: -------------------------------------> INCREMENTO E CONSEGUENTE VERIFICA DEL CONTATORE
//                                                       (SE IL LIMITE NON E' STATO SUPERATO IL
//                                                       CICLO RICOMINCIA)
////////////////////////////////////////////////////////////////////////////////////////////////////////////

Se l'esempio non ha ancora chiarificato del tutto il meccanismo delle istruzioni ciclo, proviamo a passare alle rappresentazioni pratiche, più rigorose ma forse più intuitive.

L'ISTRUZIONE CICLICA FOR
Un ciclo comodo, veloce ed efficace


//        |-> SITUAZIONE INIZIALE -------------------------------------->|                    |
//        |                 |--------> LIMITE -------------------------->| IMPOSTAZIONE CICLO |
//        |                 |                 |-> INCREMENTO ----------->|                    |
//        |                 |                 |
for (int var_contatore=1; var_contatore < 13; var_contatore++)
{
cout << "Nel ciclo numero " << var_contatore << " la variabile var_contatore è uguale a " << var_contatore << "\n";
}

Eseguendo questo semplice codice si avrà come risultato, uno sotto l'altro, tutti i numeri da 1 a 12. Per comprendere meglio prendiamo in analisi singolarmente ciascuna porzione del codice proposto:

  • "for" identifica l'inizio di un ciclo for.
  • "()" le parentesi delimitano lo spazio dove impostare come il ciclo dovrà comportarsi.
  • I ";" all'interno delle parentesi separano le tre impostazioni del ciclo.
  • "int var_contatore=0" sta a significare che dichiariamo un contatore e che gli imponiamo inizialmente di valere 0 (var_contatore è una variabile qualsiasi e 0 un valore scelto unicamente perchè serve ai nostri scopi).
  • Con "var_contatore < 13" impostiamo il limite di volte che il ciclo verrà eseguito (in questo caso 12 volte), imponendo a var_contatore un valore massimo consentito pari a 12.
  • Con "var_contatore++", in questo caso, impostiamo l'incremento di var_contatore di 1 (ovvero "var_contatore = var_contatore+1") ad ogni fine ciclo; come è noto, se avessimo messo "++var_contatore" al posto di "var_contatore++" l'incremento, invece di risultare dopo ogni ciclo, sarebbe stato effettuato prima di eseguire tutte le istruzioni interne ad esso (es. nel primo caso il primo ciclo vedrebbe la nostra variabile uguale a 2 nel secondo caso il primo ciclo vedrebbe il valore di var_contatore uguale a 1).
  • "{}" le graffe delimitano le istruzioni da eseguire nel ciclo, il quale, terminate le n ripetizioni, permette che il flusso del programma riprenda con ciò che segue la "chiusa parentesi".
  • Con "cout << "Nel ciclo numero " << var_contatore << " la variabile var_contatore è uguale a " << var_contatore << "\n";" stampiamo su schermo ad ogni esecuzione del ciclo: "Nel ciclo numero n la variabile var_contatore è uguale a n" (ad esempio il secondo ciclo risulterà: "Nel ciclo numero 2 la variabile var_contatore è uguale a 2").

L'ISTRUZIONE CICLICA WHILE
Quale il suo funzionamento e quale la sua utilità

Compreso il funzionamento di "for" sarà adesso più intuitiva l'assimilazione dell'istruzione "while", diamo quindi un'occhiata al seguente listato (tenendo sempre presente il primo esempio teorico):


// SITUAZIONE INIZIALE
int var_uno = 1;

// LIMITE
while (var_uno < 13)
{

// AZIONE
cout << "Nel ciclo numero " << var_uno << " la variabile var_uno è uguale a " << var_uno << "\n";

// INCREMENTO
var_uno++;

}

Il listato appena mostrato esegue, come è facile capire, esattamente ciò che aveva fatto il ciclo for precedentemente trattato, la differenza fondamentale sta difatti nelle modalità. Ma vediamone nel dettaglio la struttura:

  • "int var_uno = 1;" è la dichiarazione del nostro "contatore" (come è facile notare esso è del tutto esterno al nostro ciclo).
  • "while (var_uno < 13)" identifica l'inizio di un ciclo while e, tra le parentesi tonde "()" pone il limite al numero di ripetizioni del ciclo (in questo caso, ad esempio, le istruzioni interne verranno "ciclate" 12 volte).
  • "cout << "Nel ciclo numero " << var_uno << " la variabile var_uno è uguale a " << var_uno << "\n";" (come sopra) stampa su schermo il risultato, uno sotto l'altro, di ciascuna esecuzione del ciclo.
  • Con "var_uno++;" viene sancito l'incremento di 1 di var_uno ad ogni esecuzione del ciclo (è importante notare che l'incremento non si trova all'interno delle parentesi tonde ma tra le azioni da eseguire).

L'ISTRUZIONE DO WHILE
La parola riservata do


// SITUAZIONE INIZIALE
int var_uno = 1;

// DO ESEGUE L'AZIONE PRIMA DI VERIFICARE LA CONDIZIONE LIMITE
do
{

// AZIONE
cout << "Nel ciclo numero " << var_uno << " la variabile var_uno è uguale a " << var_uno << "\n";

// INCREMENTO
var_uno++;

}
// LIMITE
while (var_uno < 13);

"do" è molto simile a "while", ma la differenza che balza immediatamente all'occhio sta nel fatto che questa istruzione, invece di valutare la condizione prima di eseguire le azioni interne, esegue le azioni una volta e solo allora mette in atto la verifica. Analizziamo rapidamente che cosa accade in questi frangenti:

  • "int var_uno = 1;" è la dichiarazione del contatore esterno.
  • "do {}" identifica l'inizio di un'espressione do e fa sì che tutto quello che è contenuto nelle graffe venga eseguito immediatamente almeno una volta.
  • "cout << "Nel ciclo numero " << var_uno << " la variabile var_uno è uguale a " << var_uno << "\n";" stampa il risultato.
  • "var_uno++;" incrementa.
  • "while (var_uno < 13);" è la condizione che viene verificata dopo la prima esecuzione, se difatti var_uno, nonostante il primo ciclo, sarà ancora minore di 13 le istruzioni interne verranno ciclate ancora, in alternativa il flusso del programma riprenderà da quello che viene dopo "while (var_uno < 13);".

UN RISCHIO FREQUENTE: I CICLI INFINITI
Quando a causa di una "svista" il ciclo non ha mai termine

Soprattutto con while e do while può capitare erroneamente di impostare le condizioni limite del ciclo in modo tale da rendere sempre falso il caso limite; in questo modo si giunge così ad una ripetizione "eterna" delle istruzioni previste con conseguente (ed eventuale) blocco del sistema. Per ovviare a questo genere di errori è sempre meglio, prima di compilare il programma, cercare di immaginare l'evoluzione passo passo del flusso. Oltre a tutto ciò, in taluni casi, è possibile aiutarsi con: break, continue e goto.


// ESEMPI DI CICLI INFINITI
// Si prega di NON eseguire questo codice

// ESEMPIO 1
while (3) {
cout << "Non dovevi farlo!";
}

// ESEMPIO 2
for (int n=1; ; n++)
{
cout << n;
}

BREAK, CONTINUE E GOTO
Utili parole chiave per modificare il flusso dei cicli

Vediamo in dettaglio queste tre parole chiave:

  • "break" = Come abbiamo già potuto in parte constatare nella lezione relativa alle istruzioni condizionali, "break" fa sì che si esca dall'istruzione corrente senza che ad esempio vengano eseguiti tutti i cicli prestabiliti.
  • "continue" = Permette (in un for) di passare all'iterazione successiva del ciclo (ovvero al "giro" seguente) senza eseguire nulla del codice "scavalcato" (ciò avviene incrementando la variabile contatore nelle modalità predefinite).
  • "goto" = Consente, una volta stabilito un punto di arrivo e uno di partenza, di "saltare" da un punto all'altro del codice (questa istruzione deve essere considerata tuttavia come "l'ultima spiaggia", meglio farne un uso parsimonioso).

La teoria di queste parole chiavi è molto più macchinosa della loro effettiva messa in pratica:


// ESEMPIO DI BREAK E CONTINUE

for (int n=1; n < 13; n++)
{

if (n==3) {
cout << "Il numero 3 non deve essere pronunciato! Vado al giro successivo!\n";
continue;
}

if (n==6) {
cout << "Il numero 6 non mi piace! Esco dal ciclo!";
break;
}

cout << "Nel ciclo numero " << n << " la variabile n è uguale a " << n << "\n";
}

//-----------------------------------------------------------------------------

// ESEMPIO DI GOTO

cout << "\n\nAdesso faccio un salto!\n";

// Punto di partenza (con indicazione di arrivo)
goto puntoAtterraggio;

// Parte esclusa
cout << "\nOSTACOLO (questa cosa verrà saltata e quindi mai stampata...)\n";

// Punto di arrivo del goto
puntoAtterraggio:
cout << "\nSono arrivato! Ho evitato l'ostacolo!\n";

RIASSUNTO DELLA LEZIONE, ESEMPI E CHIARIMENTI
Quando usare una determinata struttura piuttosto che un'altra

Ciascuna delle strutture trattate in questa lezione può essere usata liberamente per fare svariate operazioni anche se talvolta una di esse può risultare più efficace di un'altra. Ecco di seguito le istruzione che abbiamo imparato affiancate da una breve descrizione sul "quando usarle" (non si tratta di regole fisse):

  • for = for è il classico ciclo del quale si vuole stabilire un incremento e un contatore in maniera semplice (si usa di solito quando il punto di partenza e quello di fine sono noti).
  • while = while permette nella sua semplicità di dar vita a cicli con sistemi di incremento ad esempio dipendenti da fattori esterni o comunque più complessi.
  • do while = equivale a while con l'unico vantaggio di un'esecuzione sicura prima della effettiva verifica della condizione limite.

Prendiamo in considerazione adesso alcune particolarità:

  • Tutti i cicli hanno la proprietà di essere "nidificate" (come le istruzioni condizionali).
  • Le condizioni limite, tramite i vari operatori che il C++ supporta, possono essere anche molto complesse (es. "while(c1==2 || c3>10 && a <6)").

Concludiamo la lezione con un esempio chiarificatore delle istruzioni appena apprese:


// ESEMPIO DI CICLO WHILE CON BREAK

int c1 = 0;

while(c1 < 5) {
cout << c1*2 << "\n";

if (c1==3) {
break;
}
c1++;
}


// ESEMPIO DI CICLO DO WHILE CON CONTINUE

int c2 = 0;

do {
cout << c2*2 << "\n";
c2++;
}while(c2 < 5);



// ESEMPIO DI CICLO FOR

for (int c3=0; c3<11; c3+=2) {
cout << c3 << "\n";

if (c2==3) {
continue;
}

}
<< INDIETRO by aFiGoZ