Lezione 4: Strutture Decisionali e l'Iterazione Fondamentale

Nelle lezioni precedenti abbiamo completato la nostra cassetta degli attrezzi con i tipi di dato, la codifica dei reali e della tabella ASCII, e i dettagli sui modificatori di dimensione. Finora, però, i nostri programmi sono stati per lo più sequenze lineari di istruzioni. In questa lezione scopriremo come alterare questo flusso per prendere decisioni complesse e ripetere porzioni di codice. Partiremo analizzando come la CPU esegue i salti a basso livello (Assembly e goto), vedremo come il teorema di Böhm-Jacopini ci garantisca la possibilità di scrivere codice pulito senza usare salti incondizionati (spaghetti code), e impareremo a usare la selezione (if/else, switch, operatore ternario) e l’iterazione base (while con break/continue) in C. Infine, faremo la nostra prima conoscenza con il debugger LLDB per ispezionare il comportamento del codice in tempo reale.
1. Dalla RAM alla Programmazione Strutturata (Sotto il Cofano)
Sezione intitolata “1. Dalla RAM alla Programmazione Strutturata (Sotto il Cofano)”Il Flusso non Lineare e il Trucco del Salto (Goto)
Sezione intitolata “Il Flusso non Lineare e il Trucco del Salto (Goto)”Come fa il computer a saltare delle righe di codice o a ripetere un blocco di istruzioni? Fisicamente, la CPU possiede un registro speciale chiamato Program Counter (PC) che memorizza l’indirizzo della RAM dell’istruzione attualmente in esecuzione.
Normalmente il PC avanza in sequenza, istruzione dopo istruzione. Per deviare questo comportamento, la CPU non conosce blocchi o parentesi graffe: esegue semplicemente dei salti (jump) caricano un indirizzo diverso all’interno del Program Counter.
Consideriamo questa struttura condizionale in C e come viene convertita in linguaggio macchina dal compilatore:
/* Codice sorgente in C */int x = 5;if (x == 5) { x = 10;}; Equivalente Assembly concettuale (con il registro R1 che contiene il valore di x)cmp R1, 5 ; Confronta il valore in R1 con il letterale 5jne FINE_IF ; Jump if Not Equal: se non sono uguali, salta a FINE_IF!mov R1, 10 ; Se R1 == 5, esegui questo blocco (scrivi 10 in R1)FINE_IF:; Il programma continua...La Flessibilità del goto e lo Spaghetti Code
Sezione intitolata “La Flessibilità del goto e lo Spaghetti Code”Anche in C è possibile scrivere salti incondizionati di basso livello abbinando l’istruzione goto a delle etichette:
int x = 10;if (x > 5) goto SALTO;printf("Questo messaggio viene ignorato.\n");
SALTO:printf("Siamo saltati direttamente qui.\n");Con il goto possiamo saltare in avanti (per saltare porzioni di codice) ma anche all’indietro (creando dei cicli). Negli anni ‘60, l’uso indiscriminato di questi salti liberi all’interno del codice portava a programmi disordinati definiti spaghetti code, complessi da comprendere e debuggare.
Il Teorema di Böhm-Jacopini
Sezione intitolata “Il Teorema di Böhm-Jacopini”Nel 1966, gli informatici italiani Corrado Böhm e Giuseppe Jacopini pubblicarono una dimostrazione fondamentale che pose fine al caos dei salti non regolamentati:
Teorema di Böhm-Jacopini
Qualsiasi algoritmo computabile può essere espresso utilizzando esclusivamente tre strutture di controllo fondamentali:
- Sequenza: esecuzione ordinata di istruzioni una dopo l’altra.
- Selezione: deviazione condizionale del flusso (es. bivio sì/no).
- Iterazione: ripetizione di un blocco finché una condizione rimane vera.
Questo teorema assicura che possiamo bandire l’uso del goto senza perdere alcuna potenza computazionale, affidando la logica del nostro codice a strutture pulite e nidificate.
Concettualizzare con i Diagrammi di Flusso (Flowchart)
Sezione intitolata “Concettualizzare con i Diagrammi di Flusso (Flowchart)”I diagrammi di flusso sono la visualizzazione grafica immediata delle tre strutture di controllo:
- Rettangolo: indica un’istruzione sequenziale.
- Rombo: indica una selezione condizionale che dirama il flusso.
- Frecce all’indietro: indicano un loop iterativo che ritorna in un punto precedente del programma.
graph TD
Start([Inizio]) --> RiempiCaldaia[Riempi la caldaia d'acqua]
RiempiCaldaia --> InserisciFiltro[Inserisci il filtro e il caffè]
InserisciFiltro --> ChiudiMoka[Chiudi la moka e mettila sul fuoco]
ChiudiMoka --> CheckUscito{Il caffè è uscito?}
CheckUscito -- No --> Attendi[Rimani in attesa]
Attendi --> CheckUscito
CheckUscito -- Sì --> SpegniFuoco[Spegni il fuoco]
SpegniFuoco --> Versa[Versa il caffè nella tazzina]
Versa --> End([Fine])
Il diagramma mostra chiaramente le tre strutture all’opera:
- Sequenza: I passaggi iniziali si susseguono linearmente (
Riempi caldaiaInserisci filtroChiudi moka). - Selezione: Il rombo decisore (
Il caffè è uscito?) separa il flusso in due percorsi alternativi basati su una risposta logica (Sì/No). - Iterazione: Il percorso che dal blocco di attesa ritorna al controllo del rombo forma un anello chiuso (ciclo) che ripete l’azione finché la condizione non cambia.
2. Le Strutture Condizionali in C
Sezione intitolata “2. Le Strutture Condizionali in C”La Selezione Completa: if, else ed else if
Sezione intitolata “La Selezione Completa: if, else ed else if”Completiamo la sintassi del blocco condizionale introducendo la via alternativa (else) e la cascata di controlli escludentisi (else if):
if (punti >= 90) { printf("Eccellente\n");} else if (punti >= 60) { printf("Sufficiente\n");} else { printf("Non sufficiente\n");}Quando una delle condizioni a cascata risulta vera, la CPU esegue il relativo blocco e salta immediatamente oltre la fine della struttura dell’intera catena di if, ignorando i test successivi.
Selezione Multipla Discreta: switch
Sezione intitolata “Selezione Multipla Discreta: switch”Quando dobbiamo confrontare una singola variabile discreta (es. intero o carattere) con molti valori fissi possibili, l’uso di molti else if risulta ridondante. Il C offre il costrutto switch:
#include <stdio.h>
int main(void) { int scelta; printf("--- MENU DISTRIBUTORE ---\n"); printf("1. Caffè (0.50€)\n"); printf("2. Tè caldo (0.60€)\n"); printf("3. Cioccolata (0.70€)\n"); printf("Inserisci la tua scelta (1-3): "); scanf("%d", &scelta);
switch (scelta) { case 1: printf("Hai selezionato: Caffè\n"); break; case 2: printf("Hai selezionato: Tè caldo\n"); break; case 3: printf("Hai selezionato: Cioccolata\n"); break; default: printf("Selezione errata!\n"); } return 0;}Il trabocchetto del Fall-Through
Se omettete l’istruzione break alla fine di un case, la CPU non si ferma! Continuerà a eseguire a cascata le istruzioni dei case successivi anche se le loro condizioni non sono verificate. Questo comportamento può essere sfruttato intenzionalmente (ad esempio per far eseguire la stessa azione a 'a' e 'A'), ma nella maggior parte dei casi l’omissione del break è un bug.
Vincoli dello switch
Sezione intitolata “Vincoli dello switch”- Può valutare solo tipi discreti (
int,char,short,long). Non si possono usareswitchcon stringhe o con numeri a virgola mobile (double). - Può verificare unicamente condizioni di uguaglianza, non relazioni d’ordine (non potete scrivere
case >= 18:).
L’Operatore Ternario (? :)
Sezione intitolata “L’Operatore Ternario (? :)”Consente di scrivere una selezione condizionale rapida per assegnare un valore a una variabile:
/* Con operatore ternario */int max = (a > b) ? a : b;
/* Con if-else equivalente */int max;if (a > b) { max = a;} else { max = b;}La sintassi è: (condizione) ? valore_se_vero : valore_se_falso;.
3. L’Iterazione Fondamentale: Il Ciclo while
Sezione intitolata “3. L’Iterazione Fondamentale: Il Ciclo while”Il Costrutto while
Sezione intitolata “Il Costrutto while”Il ciclo while ripete l’esecuzione del blocco di codice racchiuso tra le graffe finché la sua condizione di controllo rimane vera (diversa da zero).
while (condizione) { // Codice da ripetere}L’universalità del while
Nelle prossime lezioni studieremo altri tipi di cicli come for o do-while. È fondamentale comprendere che tutto ciò che si può implementare con gli altri cicli può essere espresso con un ciclo while. Esso rappresenta l’iterazione base universale.
Evitare il Loop Infinito
Sezione intitolata “Evitare il Loop Infinito”Affinché il ciclo termini, all’interno del blocco delle graffe deve esistere un’istruzione che modifichi lo stato delle variabili coinvolte nella condizione di controllo, facendola diventare prima o poi falsa (0). Altrimenti il programma rimarrà bloccato in un loop infinito.
Vediamo un esempio di divisione intera eseguita per sottrazioni successive senza usare l’operatore /:
#include <stdio.h>
int main(void) { int dividendo = 17; int divisore = 5;
int quoziente = 0; int resto = dividendo;
// Sottraiamo finché il resto è maggiore o uguale al divisore while (resto >= divisore) { resto = resto - divisore; // Aggiorna lo stato! quoziente++; }
printf("Quoziente: %d, Resto: %d\n", quoziente, resto); return 0;}Algoritmo del Massimo e Minimo (Sequenza Fissa)
Sezione intitolata “Algoritmo del Massimo e Minimo (Sequenza Fissa)”Prima di addentrarci in cicli dal comportamento dinamico, studiamo un problema classico e fondamentale dell’informatica: trovare il valore massimo e minimo all’interno di una sequenza di numeri inseriti dall’utente.
Immaginiamo di dover leggere esattamente numeri interi positivi. Per trovare gli estremi (massimo e minimo) senza dover memorizzare tutti i numeri contemporaneamente, applichiamo un algoritmo iterativo basato su valori provvisori:
- Acquisiamo il primo numero e lo impostiamo provvisoriamente sia come massimo che come minimo.
- Per ciascuno dei successivi numeri: lo confrontiamo con il massimo provvisorio (se è maggiore, aggiorniamo il massimo) e con il minimo provvisorio (se è minore, aggiorniamo il minimo).
#include <stdio.h>
int main(void) { int numero; int max; int min;
// Leggiamo il primo numero per impostare lo stato iniziale printf("Inserisci il 1° numero: "); if (scanf("%d", &numero) != 1) { printf("Errore di lettura.\n"); return 1; } max = numero; min = numero;
// Ciclo per i restanti 9 numeri int i = 2; // Contatore: indica quale numero stiamo leggendo while (i <= 10) { printf("Inserisci il %d° numero: ", i); if (scanf("%d", &numero) != 1) { printf("Errore di lettura.\n"); return 1; }
if (numero > max) { max = numero; // Aggiorna il massimo provvisorio } if (numero < min) { min = numero; // Aggiorna il minimo provvisorio } i++; // Passa al numero successivo }
printf("\n--- Risultati ---\n"); printf("Il numero massimo inserito è: %d\n", max); printf("Il numero minimo inserito è: %d\n", min);
return 0;}Modificare il Flusso del Ciclo: break e continue
Sezione intitolata “Modificare il Flusso del Ciclo: break e continue”Possiamo alterare il comportamento standard di un ciclo a metà dell’esecuzione utilizzando due istruzioni speciali:
break: esce immediatamente dal ciclowhile, saltando alla prima istruzione utile dopo il blocco.continue: interrompe l’iterazione corrente a metà, saltando le righe sottostanti per tornare subito in cima a valutare nuovamente la condizione di controllo.
Per comprendere l’utilità di questi costrutti, analizziamo un problema reale: scrivere un programma che legga una sequenza di voti d’esame universitari inseriti da tastiera. Il programma deve:
- Accettare solo voti validi compresi tra
18e30(incluso31per indicare 30 e lode), saltando qualsiasi inserimento errato tramite l’istruzionecontinue. - Interrompere l’acquisizione non appena l’utente digita il valore di sentinella
-1tramite l’istruzionebreak. - Calcolare e visualizzare alla fine: il numero di esami validi inseriti, il voto massimo, il voto minimo e la media aritmetica dei voti validi.
#include <stdio.h>
int main(void) { int voto = 0; int somma = 0; int conteggio = 0;
// Inizializziamo il massimo con il valore più basso possibile per un esame int max = 0; // Inizializziamo il minimo con il valore più alto possibile per un esame int min = 100;
printf("Inserisci i voti degli esami (compresi tra 18 e 31; inserisci -1 per terminare):\n");
while (1) { // Ciclo potenzialmente infinito, controllato all'interno printf("Inserisci voto: "); if (scanf("%d", &voto) != 1) { printf("Inserimento non valido.\n"); break; }
// Caso di uscita volontaria if (voto == -1) { break; // Esce immediatamente dal ciclo }
// Filtro di validità: i voti validi vanno da 18 a 30 (31 per lode) if (voto < 18 || voto > 31) { printf("Voto non valido! Deve essere compreso tra 18 e 31 (31 = 30L).\n"); continue; // Salta il resto del corpo del ciclo e torna in cima }
// Se siamo arrivati qui, il voto è valido. Aggiorniamo le statistiche: somma = somma + voto; conteggio++;
if (voto > max) { max = voto; } if (voto < min) { min = voto; } }
// Calcolo e stampa dei risultati if (conteggio > 0) { double media = (double)somma / conteggio; printf("\n--- Statistiche Esami ---\n"); printf("Esami superati: %d\n", conteggio); printf("Voto massimo: %d\n", max); printf("Voto minimo: %d\n", min); printf("Media voti: %.2f\n", media); } else { printf("\nNessun voto valido inserito.\n"); }
return 0;}4. Quiz di Autovalutazione
Sezione intitolata “4. Quiz di Autovalutazione”1. Quale registro della CPU memorizza fisicamente l’indirizzo dell’istruzione in esecuzione?
- A) Il registro Accumulatore.
- B) Il Program Counter (PC).
- C) Il registro Stack Pointer.
- D) Il registro di Stato (Flags).
▶ Mostra Risposta Corretta
Risposta corretta: B
Spiegazione: Il Program Counter memorizza l’indirizzo di memoria dell’istruzione corrente e viene incrementato per puntare alla successiva o modificato direttamente durante le istruzioni di salto.
2. Cosa stabilisce il Teorema di Böhm-Jacopini?
- A) Che tutti i calcolatori devono seguire l’architettura di Von Neumann.
- B) Che qualsiasi algoritmo può essere espresso usando solo Sequenza, Selezione e Iterazione.
- C) Che il compilatore C converte i tipi reali sempre usando il bias 1023.
- D) Che l’uso del
gotoè obbligatorio per scrivere cicli infiniti.
▶ Mostra Risposta Corretta
Risposta corretta: B
Spiegazione: Dimostrato nel 1966, garantisce che i tre costrutti base siano sufficienti per esprimere qualsiasi logica computazionale, rendendo l’istruzione di salto incondizionato goto non necessaria.
3. Cosa succede se si omette il comando break in uno dei blocchi case di uno switch?
- A) Il compilatore segnala un errore di sintassi e arresta la compilazione.
- B) Il programma crasha con un errore di segmentation fault.
- C) La CPU prosegue eseguendo le istruzioni dei
casesuccessivi a cascata (fall-through). - D) Lo
switchviene convertito automaticamente in una divisione intera.
▶ Mostra Risposta Corretta
Risposta corretta: C
Spiegazione: Il break serve a uscire dallo switch. Se manca, l’esecuzione prosegue linearmente sulle righe dei casi successivi, indipendentemente dal valore dei loro controlli.
4. Quale dei seguenti tipi non può essere valutato all’interno di una selezione switch?
- A)
int - B)
char - C)
double - D)
short
▶ Mostra Risposta Corretta
Risposta corretta: C
Spiegazione: Il costrutto switch in C opera esclusivamente su valori discreti convertibili in interi. I numeri in virgola mobile (double e float) e le stringhe sono esclusi.
5. Quale espressione con l’operatore ternario equivale a questo blocco?
int ris;if (valore > 0) ris = 1;else ris = 0;- A)
int ris = (valore > 0) ? 0 : 1; - B)
int ris = (valore > 0) ? 1 : 0; - C)
int ris = (valore > 0) : 1 ? 0; - D)
int ris = valore > 0;
▶ Mostra Risposta Corretta
Risposta corretta: B (anche la D è corretta in C, ma la B usa esplicitamente l’operatore ternario)
Spiegazione: La sintassi dell’operatore ternario assegna il primo valore (1) se la condizione è vera, altrimenti il secondo (0).
6. Che cos’è l’universalità del ciclo while?
- A) Significa che funziona su qualsiasi sistema operativo.
- B) Significa che qualsiasi ciclo scritto con
forodo-whilepuò essere espresso tramite ilwhile. - C) Significa che il
whilenon può mai produrre un ciclo infinito. - D) Significa che può valutare solo condizioni logiche ma non confronti numerici.
▶ Mostra Risposta Corretta
Risposta corretta: B
Spiegazione: Il while rappresenta la forma più pura ed elementare di iterazione. Gli altri cicli sono zuccheri sintattici che facilitano la scrittura, ma non aggiungono potenza di calcolo.
7. Cosa fa l’istruzione continue all’interno di un ciclo while?
- A) Esce immediatamente dal ciclo saltando alla fine del programma.
- B) Salta la parte rimanente del blocco del ciclo solo per l’iterazione corrente, ritornando in cima a valutare la condizione.
- C) Esegue di nuovo l’istruzione precedente per correggere eventuali errori.
- D) Azzera il contatore del ciclo portando la condizione a vero.
▶ Mostra Risposta Corretta
Risposta corretta: B
Spiegazione: continue interrompe solo il passaggio corrente. Riporta il flusso in cima al controllo del ciclo per l’iterazione successiva.
8. Nel programma di esempio sui voti universitari, cosa succede se l’utente inserisce la sequenza di numeri: 25, 12, 30, -1?
- A) Il programma stampa una media pari a 22.33 (escludendo solo -1).
- B) Il programma termina restituendo un errore a causa del valore 12.
- C) Il programma ignora il voto 12 (tramite
continue) e calcola le statistiche (media 27.50) su 25 e 30 dopo l’uscita tramitebreakcon -1. - D) Il programma va in loop infinito.
▶ Mostra Risposta Corretta
Risposta corretta: C
Spiegazione: Il valore 12 è fuori dall’intervallo [18, 31], quindi attiva la condizione d’errore e l’istruzione continue che salta le istruzioni di accumulo e conteggio. Il valore -1 provoca l’attivazione del break che interrompe il ciclo e avvia la stampa finale delle medie basate solo sui voti validi (25 e 30, la cui media è 27.50).
6. Esercizi Pratici
Sezione intitolata “6. Esercizi Pratici”Esercizio 1: Il Calcolo del Massimo tra tre numeri
Sezione intitolata “Esercizio 1: Il Calcolo del Massimo tra tre numeri”Scrivete un programma che legga tre numeri interi da tastiera e stampi il valore massimo tra i tre, usando una cascata di if/else ed evitando l’uso di operatori logici complessi.
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { int a, b, c; printf("Inserisci tre numeri interi: "); scanf("%d %d %d", &a, &b, &c);
int max = a;
if (b > max) { max = b; } if (c > max) { max = c; }
printf("Il valore massimo inserito è: %d\n", max); return 0;}Spiegazione dell’algoritmo:
Assumiamo inizialmente che a sia il massimo. Successivamente confrontiamo questo valore provvisorio con b ed eventualmente lo aggiorniamo, ripetendo lo stesso passaggio con c.
Esercizio 2: Calcolatore di Tariffe Distributore
Sezione intitolata “Esercizio 2: Calcolatore di Tariffe Distributore”Scrivete un programma che simuli la selezione di una scelta menu (1=Caffè, 2=Cioccolata, 3=Tè) e stampi il costo, usando lo switch con gestione del caso di errore tramite default.
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { int scelta; printf("Menu Bevande:\n1. Caffè\n2. Cioccolata\n3. Tè\nScelta: "); scanf("%d", &scelta);
switch (scelta) { case 1: printf("Costo Caffè: 0.50€\n"); break; case 2: printf("Costo Cioccolata: 0.70€\n"); break; case 3: printf("Costo Tè: 0.60€\n"); break; default: printf("Errore: Selezione non valida!\n"); } return 0;}Spiegazione dell’algoritmo:
Il costrutto switch seleziona il blocco corretto confrontando l’intero scelta. L’istruzione break garantisce l’uscita dallo switch evitando l’esecuzione del codice sottostante.
Esercizio 3: Divisione intera senza l’operatore di divisione
Sezione intitolata “Esercizio 3: Divisione intera senza l’operatore di divisione”Scrivete un programma che calcoli la divisione intera e il resto tra due numeri interi positivi usando solo sottrazioni ripetute all’interno di un ciclo while.
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { int dividendo, divisore; printf("Inserisci dividendo e divisore positivi: "); scanf("%d %d", ÷ndo, &divisore);
if (divisore <= 0 || dividendo < 0) { printf("Errore: inserisci valori validi!\n"); return 1; }
int quoziente = 0; int resto = dividendo;
while (resto >= divisore) { resto = resto - divisore; quoziente++; }
printf("Risultato: %d con resto %d\n", quoziente, resto); return 0;}Spiegazione dell’algoritmo:
Sottraiamo il divisore dal dividendo cumulato in resto fino a quando non è più possibile sottrarre senza andare in negativo. Il numero di sottrazioni effettuate corrisponde al quoziente.
Esercizio 4: Massimo Comun Divisore (MCD)
Sezione intitolata “Esercizio 4: Massimo Comun Divisore (MCD)”Implementate l’algoritmo di Euclide a sottrazioni successive per calcolare il MCD tra due numeri interi positivi letti da tastiera.
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { int a, b; printf("Inserisci due numeri interi positivi: "); scanf("%d %d", &a, &b);
if (a <= 0 || b <= 0) { printf("I numeri devono essere positivi!\n"); return 1; }
int temp_a = a; int temp_b = b;
while (temp_a != temp_b) { if (temp_a > temp_b) { temp_a = temp_a - temp_b; } else { temp_b = temp_b - temp_a; } }
printf("Il MCD tra %d e %d è %d\n", a, b, temp_a); return 0;}Spiegazione dell’algoritmo:
Ripetiamo la sottrazione del minore dal maggiore finché le due variabili temp_a e temp_b non contengono lo stesso valore, che per definizione di Euclide corrisponde al MCD.
Esercizio 5: Stampa dei soli numeri dispari con continue
Sezione intitolata “Esercizio 5: Stampa dei soli numeri dispari con continue”Scrivete un programma che stampi tutti i numeri da 1 a 15, escludendo i numeri pari tramite l’uso dell’istruzione continue all’interno di un ciclo while.
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { int i = 0; while (i < 15) { i++; if (i % 2 == 0) { continue; // Salta il resto del ciclo e torna in cima } printf("%d ", i); } printf("\n"); return 0;}Spiegazione dell’algoritmo:
A ogni iterazione incrementiamo i. Se i è pari (i % 2 == 0), l’istruzione continue fa ripartire immediatamente il ciclo dal controllo, ignorando l’istruzione printf sottostante.
Esercizio 6: Somma di numeri fino a inserimento dello zero
Sezione intitolata “Esercizio 6: Somma di numeri fino a inserimento dello zero”Scrivete un programma che continui a richiedere numeri interi all’utente sommandoli tra loro. Il ciclo deve interrompersi non appena l’utente digita il valore 0. Stampate infine la somma totale.
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { int numero = -1; // Inizializzato a un valore diverso da zero int somma = 0;
while (numero != 0) { printf("Inserisci un numero (0 per terminare): "); scanf("%d", &numero); somma = somma + numero; }
printf("La somma totale dei numeri inseriti è: %d\n", somma); return 0;}Spiegazione dell’algoritmo:
Fintanto che l’utente non inserisce 0, la condizione numero != 0 rimane vera e il ciclo accumula il valore letto nella variabile somma.
Esercizio 7: Conversione carattere maiuscolo/minuscolo
Sezione intitolata “Esercizio 7: Conversione carattere maiuscolo/minuscolo”Scrivete un programma che acquisisca un singolo carattere da tastiera. Se è una lettera maiuscola, stampate la rispettiva lettera minuscola sfruttando la tabella ASCII (senza usare funzioni di libreria), altrimenti stampate un errore.
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { char c; printf("Inserisci un carattere maiuscolo: "); scanf(" %c", &c); // Lo spazio prima di %c consuma eventuali whitespace residui
if (c >= 'A' && c <= 'Z') { // La distanza tra maiuscole e minuscole in ASCII è costante ('a' - 'A' = 32) char minuscolo = c + ('a' - 'A'); printf("Lettera minuscola: %c\n", minuscolo); } else { printf("Errore: il carattere inserito non è una lettera maiuscola!\n"); }
return 0;}Spiegazione dell’algoritmo: Sfruttiamo la codifica ordinata ASCII. Le lettere maiuscole e minuscole distano sempre 32 posizioni tra loro. Sommando questa differenza passiamo al carattere minuscolo equivalente.
Esercizio 8: Menu Distributore Ciclico con Uscita volontaria
Sezione intitolata “Esercizio 8: Menu Distributore Ciclico con Uscita volontaria”Scrivete un programma che simuli il distributore di bevande dell’Esercizio 2 all’interno di un ciclo while. Il menu deve continuare a ripresentarsi all’utente dopo ogni acquisto finché non viene selezionata l’opzione di uscita (tasto 0).
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { int scelta = -1;
while (scelta != 0) { printf("\n--- DISTRIBUTORE AUTOMATICO ---\n"); printf("1. Caffè (0.50€)\n"); printf("2. Cioccolata (0.70€)\n"); printf("3. Tè (0.60€)\n"); printf("0. Esci\n"); printf("Scelta: "); scanf("%d", &scelta);
switch (scelta) { case 0: printf("Arrivederci!\n"); break; case 1: printf("Prezzo: 0.50€\n"); break; case 2: printf("Prezzo: 0.70€\n"); break; case 3: printf("Prezzo: 0.60€\n"); break; default: printf("Scelta errata!\n"); } } return 0;}Spiegazione dell’algoritmo:
Il ciclo while continua a riproporre il menu fino a quando scelta != 0 diventa falsa. Lo switch all’interno gestisce le opzioni di acquisto e l’opzione di uscita.
Esercizio 9: Calcolo potenza senza pow
Sezione intitolata “Esercizio 9: Calcolo potenza senza pow”Scrivete un programma che calcoli la potenza base elevato esponente () per esponenti interi non negativi, usando un ciclo while e moltiplicazioni ripetute.
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { double base; int esponente; printf("Inserisci la base (reale) e l'esponente (intero positivo): "); scanf("%lf %d", &base, &esponente);
if (esponente < 0) { printf("L'esponente deve essere non negativo!\n"); return 1; }
double risultato = 1.0; int i = 0;
while (i < esponente) { risultato = risultato * base; i++; }
printf("Risultato: %.6f\n", risultato); return 0;}Spiegazione dell’algoritmo:
Inizializziamo il risultato a 1.0. Moltiplichiamo il risultato per la base tante volte quante indicate dall’esponente, usando la variabile contatore i come controllo.
Esercizio 10: Fibonacci Limitato
Sezione intitolata “Esercizio 10: Fibonacci Limitato”Scrivete un programma che stampi tutti i numeri della celebre successione di Fibonacci () che siano inferiori o uguali a un valore massimo inserito dall’utente, usando un ciclo while.
💻 Mostra Soluzione e Codice C
#include <stdio.h>
int main(void) { int limite; printf("Inserisci il valore massimo: "); scanf("%d", &limite);
int a = 1; int b = 1;
printf("Successione di Fibonacci: "); while (a <= limite) { printf("%d ", a); int successivo = a + b; a = b; b = successivo; } printf("\n"); return 0;}Spiegazione dell’algoritmo:
La successione di Fibonacci si ottiene sommando i due termini precedenti. A ogni passaggio calcoliamo il successivo, facciamo slittare in avanti i valori delle variabili a e b e ci fermiamo non appena superiamo la soglia impostata.