** CAPITOLO 5 **

- ESECUZIONE CONDIZIONALE -

Normalmente il programma viene eseguito in sequenza, ovvero
si parte da una prima istruzione, si processa la seguente e
cosi' via fino al completamento del programma stesso.
Accade pero' spesso che sia necessario modificare la
sequenza di esecuzione del flusso di programma.
Abbiamo visto in alcuni esempi precedenti l'istruzione if:
questa permette di confrontare una condizione e di eseguire
o meno alcune istruzioni a seconda dell'esito del
confronto.

- IF -

L'uso della if e' il seguente:

  if( condizione e' vera )
      esegui questa istruzione

La parola if indica al compilatore che quanto segue, fino
al primo punto e virgola o, alla prima graffa chiusa se ne
e' stata aperta una subito dopo la if( condizione), e' una
struttura di controllo condizionale.

Ecco due esempi di if:

1.

    if( a > 10 )
      istruzione;

2.

    if( a < 10 ) {
      istruzione1;
      istruzione2;
      istruzione3;
    }

Nel caso 1. se la variabile a ha valore maggiore di 10
viene eseguita la riga di codice detta istruzione e poi il
programma prosegue.

Nel caso 2. se la variabile a e' minore di 10 vengono
eseguite le tre istruzioni tra parentesi graffe.

Riportiamo una tabella degli operatori relazionali
disponibili in C per effettuare confronti:

    a == b      a e' uguale a b
    a != b      a e' diverso da b
    a >  b      a e' maggiore di b
    a >= b      a e' maggiore o uguale a b
    a <  b      a e' minore di b
    a <= b      a e' minore o uguale a b

e le condizioni sono vere solo nei casi corrispondenti.

La if ha anche una parola complementare che serve ad
estenderne l'utilizzo: else.
L'uso di else e' cosi' definito:

  if( condizione vera )
     esegui istruzione1;
  else
     esegui istruzione2;

oppure

  if( condizione vera ) {
     serie di istruzioni 1;
  } else {
     serie di istruzioni 2;
  }

Piu' istruzioni if else possono essere nidificate o unite
come in questo esempio:

1.
   if( condizione1 ) {
       istruzione1_a;
       istruzione1_b;
   } else if( condizione2 ) {
         istruzione2_a;
         istruzione2_b;
   } else
      istruzione3;

La 1. testa la condizione1.

Se la condizione1 e' vera esegue le istruzioni 1_a e 1_b.

Se la condizione1 e' falsa e se la condizione2 e' vera
esegue le istruzioni 2_a e 2_b.

Se la condizione1 e' falsa e se la condizione2 e' falsa
esegue l'istruzione3.

Prestate molta attenzione a questi costrutti: e' facile
creare situazioni in cui sezioni di codice non verranno mai
eseguite in quanto le condizioni non potranno mai
avverarsi!

Abbiamo visto che esiste una tabella di operatori
relazionali: oltre a questa vi e' una tabella di operatori
logici che possono permettere ulteriori combinazioni.
Esaminiamoli:

  &&     ||

Il simbolo && effettua una AND.
Il simbolo || effettua una OR.

Possiamo cosi' scrivere:

   if( a > b && ( c != d || e < f ) )

che sara' vera se:

   a maggiore di b AND ( c diverso da d OR e minore di f )

L'uso delle parentesi cambia la precedenza degli operatori
e serve, come in questo caso, a rendere piu' chiara la
serie dei confronti.

Occorre conoscere la precedenza di questi operatori per
scrivere codice funzionante.

Pertanto riportiamo una tabella di associativita' e
precedenze.

         OPERATORE                     ASSOCIATIVITA'
()     chiamata di funzione           da sinistra a destra
[]     indici di array
.      punto(struttura dati)
->     freccia(struttura dati)
!      NOT logico                     da destra a sinistra
~      complemento a uno
-      negazione( o meno unario)
++     incremento
--     decremento
&      indirizzo di
*      indirezione
(type) cast
sizeof dimensione di
*      moltiplicazione                da sinistra a destra
/      divisione
%      resto divisione intera
+      addizione
-      sottrazione
<<     scorrimento a sinistra
>>     scorrimento a destra
<      minore di
<=     minore o uguale a
>      maggiore di
>=     maggiore o uguale a
==     uguale a
!=     diverso da
&      AND su bit
^      XOR su bit
|      OR su bit
!      NOT su bit
&&     AND logico
||     OR logico
?:     espressione condizionale       da destra a sinistra
=      operatore di assegnamento
,      virgola                        da sinistra a destra

N.B. Alcuni di questi operatori verranno trattati nel corso
in successivi momenti.

E' importante ricordare che tutti gli operatori relazionali
e di uguaglianza

   > < >= <= !=

hanno precedenza su quelli logici

   && ||

- SWITCH -

Durante la stesura del codice puo' capitare di dover fare
confronti basati su piu' alternative.
Si puo' scrivere un codice con tante if else - else if al
fine di verificare tutte le alternative, ma vi e' un metodo
migliore: l'uso della switch.

Questa istruzione e' definita nel seguente modo:

    switch( espressione intera ) {
        case costante1:
           istruzione1;
           break;
        case costante2:
           istruzione2;
           break;
         ....
        case costanten:
           istruzionen;
           break;
        default:
           istruzione;
    }

La switch funziona in questo modo:
se l'espressione intera e' uguale alla costantex si esegue
l'istruzionex e si ritorna al normale flusso di programma;
se l'espressione intera non e' uguale ad alcuna costantex
si esegue la default e si ritorna al normale flusso di
programma.
Notate che e' stata inserita l'istruzione break alla fine
di ogni case. Se non fosse stata inserita la break (che non
e' comunque obbligatoria) si sarebbero processati
indistintamente tutti i casex seguenti a quello verificato.
Analogamente la default non e' obbligatoria ma si inserisce
solo per indicare che non e' stata verificata alcuna
condizione tra quelle previste.

Es.

   char c;

   c = 'r';

   switch( c ) {
      case 'a':
         printf( "vale a" );
         break;
      case 'b':
      case 'c':
      case 'd':
         printf( "la variabile vale %c", c );
         break;
      case 'r':
         printf( "la c e' uguale a r" );
         break;
      default:
         printf( "la c non ha alcun valore predefinito" );
  }

che stampera':

    la c e' uguale a r

se avessimo tolto il break del case 'r' avremmo avuto il
seguente output:

    la c e' uguale a r
    la c non ha alcun valore predefinito

E' stata scritta la serie dei case b, c, d di seguito:
tutti e tre i case usano la stessa istruzione per
visualizzare il risultato ed e' percio' inutile ripetere lo
stesso codice per tre volte.

L'ultima istruzione per controllare il flusso del programma
e' la GOTO.

- LA GOTO -

In C esiste una istruzione GOTO che pero' non e' analoga a
quella BASIC.
La maggior parte dei programmatori C evitano di usare la
GOTO in quanto causa di possibili anomalie di programma.

Usare la GOTO solamente in casi particolari quali la
gestione di errori ed in congiunzione della setjump
library. (Uso complesso,non scevro da errori di runtime e
poco documentato).
Ricordate che la GOTO puo' essere sempre evitata: basta
riscrivere il codice in modo piu' strutturato e dopo una
migliore analisi del problema.

Comunque la sintassi della GOTO e':

.... codice
GOTO etichetta
.... altro codice
etichetta:
.... ancora altro codice

Piu' istruzioni GOTO possono far riferimento alla stessa
etichetta.
L'etichetta deve essere contenuta all'interno della
funzione che la utilizza e non ad un'altra.
Per convenzione l'etichetta inizia sempre sulla prima
colonna a sinistra e deve essere seguita dal simbolo : (due
punti).