Costrutti del linguaggio
Introduzione ai costrutti
Il flusso del programma è gestito tramite costrutti. I costrutti valutano espressioni e definiscono un comportamento opzionale e/o ciclico.
Nota: le parentesi quadre indicano codice opzionale.
Costrutto | Esempio |
if (condizione) istruzione [else istruzione] | if (x==3) { console.log("x è uguale a 3");} else { console.log("x non è uguale a 3");}; |
for ([inizializzazione]; [condizione]; [iterazione]) istruzione | for (int i=0; i<10; i++) {console.log("x: " + x);} |
while (condizione) istruzione | int i=0;while (i<10) { console.log("x: " + x);}; |
do istruzione while (condizione) | int i=0;do { console.log("x: " + x);} while (i<10); |
switch (espressione): { case valore: istruzione; break; [case valore: istruzione; break; …] [case default: istruzione]} | switch (x): { case 1: {console.log("1"); break; }case 3: {console.log("3"); break; } case default: {console.log("default");} |
assegnazione = condizione ? espressione1 (se vero) : espressione2 (se falso) | int a = b > c ? b : c |
Costrutto if
Le espressioni logiche servono per eseguire istruzioni in modo condizionale: se una espressione logica è vera, allora vengono eseguite le istruzioni di un blocco, altrimenti (opzionalmente) quelle di un altro blocco.
La sintassi è questa:
if (espressione logica) {
istruzioni...
} else {
istruzioni...
}
In pratica con if viene valutata l’espressione logica tra parentesi e se questa è vera, allora vengono eseguite le istruzioni nel blocco successivo, altrimenti vengono eseguite le istruzioni del blocco dopo l’else. Si ricorda però che l’else è facoltativo, possiamo decidere anche di non metterlo se non ci serve.
Vediamo un paio di esempi (si riporta solo una porzione del programma).
int x;
cin >> x;
if (x == 3) {
cout << "x è uguale a 3" << endl;
}
In questo secondo esempio usiamo else.
int y;
cin >> y;
if (y > 5) {
cout << "y è maggiore di 5" << endl;
} else {
cout << "y è minore o uguale a 5" << endl;
};
Switch
Switch è un costrutto che serve ad semplificare molti if… else alternativi, come ad esempio nel seguente codice:
if (a==1) {...} else if (a==2) {...} else if (a==3) {...} ...
Il costrutto switch offre una sintassi più elegante per fare la stessa cosa.
switch (a) {
case 1: {
... break;
}
case 2: {
... break;
}
case 3: {
... break;
}
default: {
...
}
}
Esempio:
int a, b;
char x;
cout << "Inserisci a: ";
cin >> a;
cout << "Inserisci b: ";
cin >> b;
cout << "Inserisci operazione (+ - * /): ";
cin > x;
switch (x) {
case "+": {
cout << a+b;
break;
}
case "-": {
cout << a-b;
break;
}
case "*": {
cout << a*b;
break;
}
case "/": {
cout << a/b;
break;
}
Costrutto while
Quando vogliamo eseguire molte volte le stesse istruzioni (ad esempio per contare e fare calcoli ripetitivi) ci serve un altro costrutto fondamentale, il while. Ecco la sintassi:
while (espressione logica) {
istruzioni...
}
While valuta una espressione e se questa è vera, esegue il blocco di istruzioni. Al termine della loro esecuzione, viene rieseguita while di nuovo. Se l’espressione è ancora vera, viene rieseguito di nuovo il gruppo di istruzioni, e così via.
Naturalmente per evitare che il ciclo non duri in eterno l’espressione logica del while deve valutare ad ogni ciclo qualcosa che è cambiato nel ciclo. Lo vediamo bene nel seguente esempio:
int i = 0; // inizializzazione
while (i < 10) { // condizione
cout << i;
i = i + 1; // modifica della variabile
}
Come si vede nel while vengono ripetute le caratteristiche classiche del ciclo: l’inizializzazione di una variabile di controllo, che viene effettuata prima del while, la modifica della variabile avviene nel ciclo, ed il controllo avviene nell’espressione while stessa. . La condizione viene ripetuta fino a quando la condizione diventa falsa. E’ compito del programmatore fare in modo che il ciclo non diventi infinito, facendo in modo che la condizione cambi come nell’esempio riportato.
Nota: il teorema di Bohm-Jacopini dimostra che con le sole istruzioni di assegnazione/input/output, il costrutto if e il costrutto while si riesce a realizzare qualsiasi tipo di algoritmo su qualsiasi tipo di computer, e che anzi ogni programma informatico si riduce a queste tre tipologie di istruzioni.
Costrutto do while
Il costrutto do while è molto simile al costrutto while:
do {
istruzioni...
} while(espressione logica)
Mentre While valuta una espressione prima di eseguite il ciclo, Do-While la valuta DOPO l’esecuzione del ciclo. Questo significa che c’è sempre almeno una esecuzione, e solo dopo viene valutata l’espressione per ri-eseguire il ciclo. Se l’espressione è vera, viene rieseguito di nuovo il gruppo di istruzioni, e così via.
Do While è utile quando si vuole richiedere un input all’utente, verificare se è corretto, e solo se valido proseguire. In queste situazioni il ciclo va eseguito almeno una volta e con Do-While si scrive meno codice.
Costrutto for
Il costrutto for è un costrutto alternativo a while, dove inizializzazione, controllo e modifica della variabile di controllo sono inserite tutte insieme, in modo da migliorare la leggibilità del codice:
for(inizializzazione; condizione; modifica) {
istruzioni...
}
Ad esempio:
for (int i=0; i<10; i++) {
cout << i;
}
Operatori di assegnazione unari, binari e ternari
Si tratta di operatori speciali, già visti in qualche esempio e che riassumiamo qui:
- Operatori unari ++, — : consentono di incrementare o decrementare un valore numerico:
esempio:a++ <--> a = a + 1
a-- <--> a = a - 1
Sono consentiti solo addizione e sottrazione unitaria - Operatori binari +=, -=, *= /= : consentono di applicare il secondo operando al primo e memorizzare il risultato nel primo operatore.
Esempio:a *= 3 <--> a = a * 3
- Operatore ternario: consente di assegnare ad una variabile un valore se è vera una condizione, o un altro se è falsa.
Esempio:a = b > c ? 3 : 1
Va letto in questo modo: se b è maggiore di c allora a prenderà valore 3, altrimenti valore 1. L’operatore ternario è una soluzione molto più elegante di un if else perchè occupa una riga sola di codice.
Tipologie di cicli
Nella programmazione strutturata possiamo determinare due tipologie di ciclo:
- il ciclo ad iterazione indefinita: in questo scenario non è noto al programma quante volte dovrà essere eseguito un determinato ciclo, perché la condizione di valutazione dipende da fattori esterni al ciclo stesso. Ad esempio se la condizione del ciclo prevede un controllo dei dati inseriti dall’utente ed il ciclo si ripete fino a quando l’utente non inserisce dati validi, questa condizione può essere ripetuta indefinitivamente. In queste situazioni è opportuno utilizzare il ciclo while oppure do while come in questo esempio:
int value;
do {
cout << "Inserisci un valore tra 1 e 10: ";
cin >> value;
} while (value >= 1 && value <= 10);
- il ciclo ad iterazione definita: in questo scenario invece il programma in esecuzione ha valorizzato il numero di volte che eseguirà il ciclo, o tramite un valore literal (un numero) oppure perché memorizzato in una variabile. In questo caso il costrutto for è il più adatto perché permette di sintetizzare in un posto solo tutte le condizioni del ciclo, come in questo esempio in cui vogliamo sommare tutti i numeri tra 1 e n inserito dall’utente:
int n;
cout << "Inserisci un valore: ";
cin >> value;
int sum = 0;
for (int i=0; i<n; i++) {
sum += i;
}
cout << sum << endl;