Istruzione SELECT CASE in Fortran

L'istruzione SELECT CASE in Fortran è un'alternativa chiara e strutturata ai blocchi IF-ELSE IF, permettendo di eseguire diversi blocchi di codice in base al valore di un'espressione intera, carattere o logica.

Questo costrutto migliora la leggibilità e la manutenzione del codice, specialmente quando ci sono molte condizioni esclusive. In questa lezione vediamo la sintassi di SELECT CASE, il suo funzionamento e alcuni esempi pratici per comprendere l'importanza dell'uso di CASE DEFAULT.

L'istruzione SELECT CASE

L'istruzione SELECT CASE è una forma alternativa di controllo del flusso in Fortran.

Essa permette di eseguire un blocco di codice specifico in base al valore di un'espressione numerica, carattere o logica.

La forma generale dell'istruzione CASE è:

[nome:] SELECT CASE (espressione)
    CASE (selettore_1) [nome]
        Istruzione 1
        Istruzione 2
        ...
    CASE (selettore_2) [nome]
        Istruzione 1
        Istruzione 2
        ...
    CASE DEFAULT [nome]
        Istruzione 1
        Istruzione 2
        ...
END SELECT [nome]
  • Se il valore di espressione corrisponde a un intervallo specificato in selettore_1, viene eseguito Blocco 1.
  • Se il valore rientra in selettore_2, viene eseguito Blocco 2.
  • Il blocco CASE DEFAULT viene eseguito se espressione non corrisponde a nessun caso precedente.
  • Il blocco DEFAULT è opzionale, ma è consigliabile usarlo per gestire eventuali input non previsti.

Il diagramma di flusso dell'istruzione SELECT CASE è mostrato nella figura seguente:

Diagramma di flusso dell'istruzione SELECT CASE
Figura 1: Diagramma di flusso dell'istruzione SELECT CASE

È possibile assegnare un nome a un'istruzione CASE:

  • Deve essere univoco all'interno dell'unità di programma.
  • Se un nome viene assegnato a SELECT CASE, lo stesso deve apparire nell'END SELECT.
  • L'uso dei nomi è opzionale per i singoli CASE, ma se presenti devono corrispondere a quello dell'END SELECT.

Per quanto riguarda l'espressione, essa deve rispettare le seguenti regole:

  • espressione può essere un numero intero, un carattere o un valore logico.
  • I selettori CASE devono essere mutuamente esclusivi, cioè un valore non può rientrare in più di un caso.
  • I selettori possono essere specificati come valori singoli, intervalli o liste di valori.

Per chiarire meglio come funziona l'istruzione SELECT CASE studiamo qualche esempio.

Esempio: Controllo della Temperatura

Vediamo un esempio di istruzione CASE che stampa un messaggio in base al valore di una temperatura espressa in gradi Celsius:

INTEGER :: temp_c  ! Temperatura in gradi Celsius
...
temp: SELECT CASE (temp_c)
    CASE (: -1)
        ! Questo caso gestisce temperature sotto lo zero
        ! ossia da -1 in giù
        WRITE (*,*) "Oggi si congela!"
    CASE (0)
        ! Temperatura esattamente a zero
        WRITE (*,*) "Oggi siamo esattamente al punto di congelamento."
    CASE (1:20)
        ! Temperatura tra 1 e 20 gradi
        WRITE (*,*) "Oggi fa fresco."
    CASE (21:33)
        ! Temperatura tra 21 e 33 gradi
        WRITE (*,*) "Oggi fa caldo."
    CASE (34:)
        ! Temperature superiori a 34 gradi
        WRITE (*,*) "Oggi fa molto caldo!"
END SELECT temp

Esaminiamo il codice sopra:

  • Il valore di temp_c determina quale caso viene selezionato.
  • Se la temperatura è minore di 0, viene stampato "Oggi si congela!".
  • Se è 0, viene stampato "Oggi siamo esattamente al punto di congelamento.".
  • Se è tra 1 e 20, viene stampato "Oggi fa fresco.".
  • Se è tra 21 e 33, viene stampato "Oggi fa caldo.".
  • Se è maggiore di 34, viene stampato "Oggi fa molto caldo!".

Da notare che abbiamo espresso i singoli casi sia come valori singoli che come intervalli.

Formati Accettati per i Selettori CASE

Dopo aver esaminato l'esempio di sopra, è importante notare che i selettori CASE possono assumere diverse forme.

Un selettore può assumere cinque forme. Le prime quattro sono le seguenti:

  • valore: Esegue il blocco se espressione == valore
  • valore_minimo:: Esegue il blocco se valore_minimo <= espressione
  • :valore_massimo: Esegue il blocco se espressione <= valore_massimo
  • valore_minimo:valore_massimo: Esegue il blocco se valore_minimo <= espressione <= valore_massimo

L'ultima forma è una lista di valori separati da virgole:

  • valore_1, valore_2, ..., valore_n: Esegue il blocco se espressione == valore_1 o espressione == valore_2 o ... o espressione == valore_n

Esempio: Numeri Pari e Dispari

Analizziamo un altro esempio per comprendere meglio l'istruzione SELECT CASE.

Vogliamo realizzare un programma che determini se un numero intero compreso tra 1 e 10 è pari o dispari:

INTEGER :: value
...
SELECT CASE (value)
    CASE (1,3,5,7,9)
        ! Caso 1: Lista dei numeri dispari
        WRITE (*,*) 'Il valore è dispari.'
    CASE (2,4,6,8,10)
        ! Caso 2: Lista dei numeri pari
        WRITE (*,*) 'Il valore è pari.'
    CASE (11:)
        ! Caso 3: Valore troppo alto
        WRITE (*,*) 'Il valore è troppo alto.'
    CASE DEFAULT
        ! Caso 4: Valore pari a zero o negativo
        WRITE (*,*) 'Il valore è zero o negativo.'
END SELECT

In questo caso abbiamo adoperato il caso di default, CASE DEFAULT, per gestire tutti i valori non previsti. In particolare, se value è maggiore di 10, viene stampato "Il valore è troppo alto.", mentre se è zero o negativo, viene stampato "Il valore è zero o negativo.".

Consiglio

Includere sempre il blocco CASE DEFAULT nelle istruzioni SELECT CASE

Includiamo sempre un blocco CASE DEFAULT nelle istruzioni SELECT CASE per gestire errori logici o input non validi.

L'istruzione SELECT CASE è un'alternativa strutturata e leggibile agli IF annidati, ideale quando si hanno molte opzioni esclusive.

Esempio: Selezione del Giorno della Settimana

Scriviamo un programma che legge un numero intero dalla tastiera e visualizza il giorno della settimana corrispondente.

Il programma deve gestire anche il caso in cui l'utente inserisca un valore non valido.

In questo esempio:

  1. Chiediamo all'utente di inserire un numero intero tra 1 e 7.
  2. Usiamo un'istruzione SELECT CASE per assegnare il giorno della settimana corrispondente, considerando lunedì come il primo giorno della settimana.
  3. Aggiungiamo un CASE DEFAULT per gestire input non validi.

Il programma risultante è mostrato di seguito.

PROGRAM giorno_settimana
!
! Scopo:
! Questo programma mostra il giorno della settimana 
! corrispondente a un valore intero inserito dall'utente.
!
IMPLICIT NONE

! Dizionario dei dati: dichiarazione delle variabili
CHARACTER(len=17) :: c_giorno ! Stringa contenente il nome del giorno
INTEGER :: i_giorno           ! Numero intero del giorno della settimana

! Chiediamo all'utente di inserire un numero da 1 a 7
WRITE (*,*) 'Inserisci il numero del giorno della settimana (1-7): '
READ (*,*) i_day

! Selezioniamo il giorno corrispondente
SELECT CASE (i_giorno)
    CASE (1)
        c_giorno = 'Lunedì'
    CASE (2)
        c_giorno = 'Martedì'
    CASE (3)
        c_giorno = 'Mercoledì'
    CASE (4)
        c_giorno = 'Giovedì'
    CASE (5)
        c_giorno = 'Venerdì'
    CASE (6)
        c_giorno = 'Sabato'
    CASE (7)
        c_giorno = 'Domenica'
    CASE DEFAULT
        c_giorno = 'Giorno non valido'
END SELECT

! Visualizziamo il giorno corrispondente
WRITE (*,*) 'Giorno = ', c_giorno

END PROGRAM day_of_week

Se il programma viene compilato ed eseguito con diversi valori di input, otteniamo:

$ ./giorno_settimana
Inserisci il numero del giorno della settimana (1-7): 1
Giorno = Lunedì
$ ./giorno_settimana
Inserisci il numero del giorno della settimana (1-7): 4
Giorno = Giovedì
$ ./giorno_settimana
Inserisci il numero del giorno della settimana (1-7): 8
Giorno = Giorno non valido

In questo esempio:

  • Il programma fornisce i giorni corretti per i valori validi da 1 a 7.
  • Se l'utente inserisce un numero fuori intervallo, viene restituito il messaggio "Giorno non valido" grazie al CASE DEFAULT.
  • L'uso dell'istruzione SELECT CASE rende il codice più leggibile rispetto a un blocco IF-ELSE IF.
  • Quando abbiamo dichiarato la variabile c_giorno abbiamo impostato come lunghezza massima 17 caratteri, in modo da poter il risultato più lungo possibile, ovvero "Giorno non valido".

Esempio: Determinare se un giorno è feriale o festivo

Scriviamo un programma che legge il nome di un giorno della settimana dalla tastiera e visualizza se è un giorno feriale ("Feriale") o un giorno festivo ("Festivo").

Il programma deve gestire anche l'eventualità in cui venga inserito un valore non valido.

In questo esempio:

  1. L'utente inserisce il nome di un giorno della settimana.
  2. L'istruzione SELECT CASE verifica se il giorno è feriale o festivo.
  3. Aggiungiamo un CASE DEFAULT per gestire input non validi.

Il programma risultante è mostrato di seguito.

PROGRAM feriale_festivo
!
! Scopo:
! Questo programma accetta una stringa con il nome di un giorno della settimana
! e risponde con un messaggio che indica se è un giorno feriale o festivo.
!
IMPLICIT NONE

! Dichiarazione delle variabili usate nel programma
CHARACTER(len=9)  :: giorno       ! Stringa contenente il nome del giorno
CHARACTER(len=17) :: tipo_giorno  ! Stringa contenente il tipo di giorno

! Chiediamo all'utente di inserire un giorno della settimana
WRITE (*,*) 'Inserisci il nome del giorno: '
READ (*,*) giorno

! Determiniamo se il giorno è feriale o festivo
SELECT CASE (giorno)
    CASE ('Lunedì','Martedì','Mercoledì','Giovedì','Venerdì')
        tipo_giorno = 'Feriale'
    CASE ('Sabato','Domenica')
        tipo_giorno = 'Festivo'
    CASE DEFAULT
        tipo_giorno = 'Giorno non valido'
END SELECT

! Visualizziamo il risultato
WRITE (*,*) 'Tipo di giorno = ', tipo_giorno

END PROGRAM feriale_festivo

Se il programma viene compilato ed eseguito con diversi valori di input, otteniamo:

$ ./feriale_festivo
Inserisci il nome del giorno: Lunedì
Tipo di giorno = Feriale
$ ./feriale_festivo
Inserisci il nome del giorno: Domenica
Tipo di giorno = Festivo
$ ./feriale_festivo
Inserisci il nome del giorno: Festività
Tipo di giorno = Giorno non valido

Notiamo che:

  • Il programma assegna correttamente la categoria "Feriale" ai giorni da lunedì a venerdì.
  • I giorni sabato e domenica sono classificati come "Festivo".
  • Se l'utente inserisce un nome non valido, il programma risponde con "Giorno non valido" grazie all'uso di CASE DEFAULT.
  • L'uso dell'istruzione SELECT CASE semplifica la gestione delle stringhe rispetto a un blocco IF-ELSE IF.

In Sintesi

In questa lezione abbiamo studiato che:

  • L'istruzione SELECT CASE permette di eseguire blocchi di codice basati sul valore di un'espressione, migliorando la leggibilità rispetto a IF-ELSE IF.
  • Il valore valutato (espressione) può essere un numero intero, un carattere, un valore logico oppure un'intera espressione e viene confrontato con i selettori CASE.
  • I selettori CASE devono essere mutuamente esclusivi, per evitare sovrapposizioni di condizioni.
  • Il blocco CASE DEFAULT è essenziale per gestire valori non previsti, evitando errori logici nel programma.
  • I selettori CASE possono assumere diverse forme, come valori singoli, intervalli (low:high) o liste di valori separati da virgole.
  • Gli esempi pratici mostrano l'uso di SELECT CASE per categorizzare la temperatura e determinare se un numero è pari o dispari.
  • Usare SELECT CASE rende il codice più leggibile e strutturato, particolarmente utile quando ci sono molte condizioni esclusive.