Unità 1

I linguaggi di programmazione

I linguaggi di programmazione permettono di scrivere algoritmi inter­pretabili da un sistema di elaborazione. Un algoritmo scritto in un linguaggio di programmazione viene chiamato programma e il processo di scrittura del programma, a partire dall’algoritmo, viene chiamato codifica. I linguaggi di programmazione sono costituiti da un alfabeto e da un insieme di regole che devono essere rispettate per scrivere programmi sintatticamente corretti.

Il linguaggio macchina costituito da zero ed uno è l'unico che pilota direttamente le unità fisiche dell'elaboratore in quanto è l’unico comprensibile dall’elaboratore stesso. È però estremamente complicato scrivere programmi in tale linguaggio naturale per la macchina ma completamente innaturale per l’uomo. Per poter permettere un dialogo più semplice con la macchina sono nati i linguaggi di programmazione.

Il più vecchio linguaggio di programmazione è il linguaggio assembly. Il linguaggio assembly è una rappresentazione simbolica del linguag­gio macchina. La scrittura di programmi è enormemente semplificata rispetto a quest'ultimo. Per essere eseguito dall'elaboratore un pro­gramma in linguaggio assembly deve essere tradotto in linguaggio macchina; tale lavoro è a carico di un programma detto assemblatore. Questi due tipi di linguaggi, detti anche linguaggi di basso livello sono propri di ogni macchina.

I linguaggi di alto livello sono più vicini al linguaggio naturale, sono orientati ai problemi piuttosto che all'architettura della macchina. Non fanno riferimento ai registri fisicamente presenti sulla macchina ma a variabili. Per essere eseguiti devono essere tradotti in linguaggio macchina, e tale traduzione viene svolta da un programma detto compilatore.

I linguaggi di alto livello sono in larga misura indipendenti dalla macchina, possono essere eseguiti su qualsiasi elaboratore a patto che esista il corrispondente compilatore che ne permetta la traduzione.

I linguaggi di alto livello si caratterizzano per essere orientati a specifiche aree applicative. Questi linguaggi vengono anche detti della terza generazione.

Per ultimi in ordine di tempo sono arrivati i linguaggi della quarta generazione, ancora più spiccatamente rivolti a specifiche aree appli­cative e, nell'ambito del loro orientamento, utilizzabili in modo intuivo dall'utente non esperto. Il più famoso di questi è SQL (Structured Query Language), che opera su basi dati relazionali. I linguaggi di IV generazione sono detti non procedurali poiché l'utente specifica la funzione che vuole svolgere senza entrare nel dettaglio di come verrà effettivamente svolta.

Il linguaggio C e il C++

Nel 1972, presso i Bell Laboratories, Dennis Ritchie progettava e realizzava la prima versione del linguaggio C. Ritchie aveva ripreso e sviluppato molti dei principi e dei costrutti sintattici del linguaggio BCPL, sviluppato da Martin Richards, e del linguaggio B, sviluppato da Ken Thompson, l'autore del sistema operativo Unix. Successiva­mente gli stessi Ritchie e Thompson riscrissero in C il codice di Unix.

Il C si distingueva dai suoi predecessori per il fatto di implementare una vasta gamma di tipi di dati (carattere, interi, numeri in virgola mobile, strutture) non originariamente previsti dagli altri due linguag­gi. Da allora ad oggi il C ha subito trasformazioni: la sua sintassi è stata affinata, soprattutto in conseguenza della estensione object-oriented (C++). Il C++, come messo in evidenza dallo stesso nome, rappresenta una evoluzione del linguaggio C: il suo progettatore (Bjarne Stroustrup) quando si pose il problema di trovare uno strumento che implementasse le classi e la programmazione ad oggetti, invece di costruire un nuovo linguaggio di programmazione, pensò bene di estendere un linguaggio già esistente, il C appunto, aggiungendo nuove funzionalità. In questo modo, contenendo il C++ il linguaggio C come sottoinsieme, si poteva riutilizzare tutto il patrimonio di conoscenze acquisito dai programmatori in C (linguaggio estremamente diffuso in ambito di ricerca) e si poteva fare in modo che tali programmatori avessero la possibilità di acquisire le nuove tecniche di programmazione senza essere costretti ad imparare un nuovo linguaggio e quindi senza essere costretti a disperdere il patrimonio di conoscenze già in loro possesso. Così le estensioni ad oggetti hanno fornito ulteriore linfa vitale al linguaggio C.

Struttura di un programma

Iniziamo esaminando il programma del seguente listato.


	#include<iostream.h>
	
	main(){
	  cout << "abc";
	  cout << "def";
	  cout << "ghi";
	  cout << "lmn";
	  cout << "opqrs";
	  cout << "tuvz";
	}
Eseguendolo verrà visualizzata la stringa delle lettere dell’alfabeto italiano:

abcdefghilmnopqrstuvz

Dalla parola main, seguita da parentesi tonda aperta e chiusa, inizia l'esecuzione del programma. Il corpo del programma, che comincia dalla parentesi graffa aperta e finisce alla parentesi graffa chiusa, è composto da una serie di istruzioni che cominciano con cout, sono seguite dal doppio simbolo << e che verranno eseguite se­quenzialmente. Si tratta di operazioni che riguardano l’invio di stringhe (sequenze di caratteri racchiuse fra doppi apici) verso una unità di output: nel nostro caso il monitor. Nell’esempio proposto cout sta ad indicare il canale di output e il simbolo << è l’operatore di inserimento. L’istruzione cout << “abc”; si potrebbe così tradurre: inserisci nel canale di output la stringa specificata. Per quanto riguarda l’instradamento verso il canale, per il momento, si può pensare come ad una conduttura che porta al monitor e nella quale si insericono una di seguito all’altra le stringhe specificate.

Ogni istruzione deve terminare con un carattere di punto e virgola.

Per poter utilizzare cout, come le altre funzioni di entrata/uscita, si deve inserire all'inizio del testo la linea

#include <iostream.h>

che awerte il compilatore di includere i riferimenti alla libreria dei canali standard di input/output (iostream sta per canali di input/output).

Il C++ distingue tra lettere maiuscole e minuscole; dunque occorre fare attenzio­ne, se si scrive MAIN() o Main() non si fa riferimento a main().

La struttura del programma C che abbiamo usato nell'esempio è:


	inclusione_librerie
	main(){
	  istruzione1
	  istruzione2
	  istruzione3
	  ........
	  istruzioneN
	}

Il punto e virgola conclude l’istruzione.

Se si desidera che ogni stringa venga prodotta su una linea separata, si deve inserire \n nel canale subito dopo la stringa e prima della chiusura dei doppi apici, come nel seguente listato.


	#include <iostream.h>
	main(){
	  cout << "abc"   << “\n”;
	  cout << "def"   << “\n”;
	  cout << "ghi"   << “\n”;
	  cout << "lmn"   << “\n”;
	  cout << "opqrs" << “\n”;
	  cout << "tuvz"  << “\n”;
	}
Eseguendo il programma si otterrà la visualizzazione delle seguenti stringhe di caratteri

	abc
	def
	ghi
	lmn
	opqrs
	tuvz

In questo caso la prima stringa (abc) viene stampata su video a partire dalla posizione attuale del cursore. Se si vuole cominciare la stampa delle stringhe da una nuova riga basta inserire \n anche all’inizio o in qualsiasi punto anche all’interno della stringa da stampare come nei seguenti esempi:


	cout << “\n” << “abc” << “\n”;
	cout << “\n abc \n def”;

Qui prima si passa ad una nuova riga, poi si stampa la stringa specificata e quindi si posiziona il cursore in una nuova riga.

In generale è bene tenere presente che l’effetto di ogni cout è quello di stampare a partire dalla posizione in cui si trovava il cursore (in generale a destra dell’ultima stampa). Per poter modificare tale comportamento è necessario inserire gli opportuni caratteri di controllo. In effetti la sequenza \n corrisponde ad un solo carattere, quello di nuova linea (newline).

Nel canale di output possono inserirsi altri caratteri di controllo di cui si forniscono di seguito quelli che hanno utilizzo più frequente:

 

Variabili e assegnamenti

Supponiamo di voler calcolare l'area di un rettangolo i cui lati hanno valori interi. Entrano in gioco due variabili, la base e l'altezza, il cui prodotto è ancora un valore intero, l'area appunto.


	#include <iostream.h>

	// Calcolo area rettangolo 

	main(){
	  int base;
	  int altezza;
	  int area;

	  base = 3;
	  altezza = 7;
	  area = base*altezza;
	  cout << area;
	}

Per rendere evidente la funzione espletata dal programma si è inserito un commento:

// Calcolo area rettangolo

Il doppio simbolo // indica inizio di commento. Tutto ciò che segue fino alla fine della riga non viene preso in considerazione dal compilatore: serve solo a scopo documentativo.

I commenti possono estendersi su più linee e apparire in qualsiasi parte del programma. Naturalmente, per quanto notato prima, il doppio // deve precedere ogni commento in una nuova riga. Se il commento si estende su più righe può essere più comodo adottare un altro sistema: fare precedere il commento da /* e inserire */ alla fine del commento. Tutto ciò che appare nelle zone così racchiuse non viene preso in considerazione dal compilatore e non ha alcuna influenza sul funzionamento del programma, è però importantissimo per chi legge il programma: è infatti nelle righe di commento che viene specificato il senso delle istruzioni che seguiranno. Cosa, questa, non immediatamente comprensibile se si leggono semplicemente le istruzioni del linguaggio.

Per sintetizzare le differenze di uso fra i due simbolismi dei commenti si può dire che:

Subito dopo main() sono presenti le dichiarazioni delle variabili intere necessarie:

int base; int altezza; int area;

La parola chiave int specifica che l'identificatore che lo segue si rife­risce ad una variabile di tipo intero; dunque base, altezza e area sono variabili di questo tipo.

Anche le dichiarazioni così come le altre istruzioni devono terminare con un punto e virgola. Nel nostro esempio alla dichiarazione del tipo della variabile corrisponde anche la sua definizione che fa sì che le venga riservato uno spazio in memoria centrale.

Il nome di una variabile la identifica, il suo tipo ne definisce la dimensione e l'insieme delle operazioni che vi si possono effettuare. La dimensione può variare rispetto all'implementazione; molte versioni del C++, come quelle sotto il sistema operativo MS DOS per esempio, riservano per gli int uno spazio di due byte, il che permette di poter lavorare su interi che vanno da  32768 a +32767, altre implementazioni, come per esempio quelle per ambiente Windows, riservano uno spazio di quattro byte permettendo valori compresi fra -2.147.483.648 e +2.147.483.647. Tra le operazioni permesse fra int vi sono: la somma (+), la sottrazione (-), il prodotto (*) e la divisione (/).

Effettuata la dichiarazione, la variabile può essere utilizzata. L'istruzione

base = 3;

assegna alla variabile base il valore 3; cioè inserisce nello spazio di memoria riservato a tale variabile il valore indicato. Effetto analogo avrà altezza=7. L'assegnamento è dunque realizzato mediante l'operatore = .

Nel linguaggio C++ è possibile assegnare lo stesso valore a più variabili contemporaneamente. Per esempio se le dimensioni riguardavano un quadrato, si sarebbe potuto scrivere:

base = altezza = 5;

In questo caso prima verrebbe assegnato il valore 5 alla variabile altezza e quindi, il risultato dell’assegnazione (cioè 5), viene assegnato alla variabile base.

L'istruzione:

        area = base * altezza;

assegna alla variabile area il prodotto dei valori di base e altezza .

L'operatore asterisco effettua l'operazione di prodotto tra la variabile che lo precede e quella che lo segue, è dunque un operatore binario.

L'ultima istruzione

cout << area;


visualizza 21, il valore della variabile area.


Le dichiarazioni delle variabili dello stesso tipo possono essere scritte in sequenza separate da una virgola:


int base,altezza,area;

 

Dopo la dichiarazione di tipo sono specificati gli identificatori di variabile, che possono essere in numero qualsiasi, separati da virgola e chiusi da un punto e virgola. In generale quindi la dichiarazione di variabili ha la seguente forma:


tipo lista_di identificatori;


Esistono inoltre delle regole da rispettare nella costruzione degli identificatori: devono iniziare con una lettera o con un carattere di sottolineatura _ e possono contenere lettere, cifre e _. Per quanto riguarda la lunghezza occorre tenere presente che soltanto i primi trentadue caratteri sono significativi, anche se nelle versioni del C meno recenti questo limite scende a otto caratteri. Sarebbe comunque opportuno non iniziare il nome della variabile con il carattere di sottolineatura ed è bene tenere presente che le lettere accentate, permesse dalla lingua italiana, non sono considerate lettere ma segni grafici e le lettere maiuscole sono considerate diverse dalle rispettive minuscole.


Oltre a rispettare le regole precedentemente enunciate, un identifica­tore non può essere una parola chiave del linguaggio, né può essere uguale ad un nome di funzione libreria o scritta dal programmatore.


Allo scopo di rendere più chiaro l'effetto ottenuto dal programma dell'esempio precedente, si possono visualizzare i valori delle variabili base e altezza. È opportuno, per motivi di chiarezza, far precedere la visualizzazione dei valori da una descrizione.



	cout << "Base: "     << base; 
	cout << " Altezza: " << altezza; 
	cout << " Area: "    << area;

Quello che si ottiene in esecuzione è


Base: 3 Altezza: 7 Area: 21


Per ottenere una distanza maggiore tra il valore di base e altezza e le seguenti descrizioni si possono aggiungere ulteriori spazi


	cout << "Base: "      << base; 
	cout << "\tAltezza: " << altezza; 
	cout << "\tArea: "    << area;

così da avere


	Base: 3    Altezza: 7    Area: 21

Per far in modo che ad ogni visualizzazione corrisponda un salto riga si deve inserire \n:


	cout << "Base: "    << base    << “\n”;
	cout << "Altezza: " << altezza << “\n”;
	cout << "Area: "    << area    << “\n”;

Osserviamo nel listato il programma C++ modificato seguendo alcune delle caratteristiche introdotte.


	#include <iostream.h>

	// Calcolo area rettangolo 

	main(){
	  int base,altezza,area;

	  base = 3;
	  altezza = 7;
	  area = base*altezza;

	  cout << “Base: ” << base << “ Altezza: ”<< altezza;
	  cout << “\nArea: ” << area; 
	}

L'esecuzione del programma avrà il seguente effetto:


Base: 3 Altezza: 7

Area: 21


Mentre int è una parola chiave del C++ e fa parte integrante del linguaggio, base, altezza e area sono identificatori di variabili scelti a nostra discrezione. Lo stesso effetto avremmo ottenuto utilizzando al loro posto altri nomi generici quali x, y e z solo che il programma sarebbe risultato meno comprensibile.


La forma grafica data al programma è del tutto opzionale; una volta rispettata la sequenzialità e la sintassi, la scrittura del codice è libera. In particolare più istruzioni possono essere scritte sulla stessa linea. E indubbio che il programma risulterà notevolmente meno leggibile del precedente.


Lo stile grafico facilita enormemente il riconoscimento dei vari pezzi di programma e consente una diminuzione di tempo nelle modifiche, negli ampliamenti e nella correzione degli errori. In generale è inoltre bene dare alle variabili dei nomi significativi, in modo che, quando si debba intervenire a distanza di tempo sullo stesso program­ma, si possa facilmente ricostruire l'uso che si è fatto di una certa variabile.

Inizio


Costanti


Nel programma visto precedentemente i valori di base e al­tezza sono costanti, dato che non variano durante l'esecuzione del programma. Evidentemente avremmo potuto scrivere direttamente


area = 3 * 7;


Quando un certo valore viene utilizzato in modo ricorrente è opportuno rimpiazzarlo con un nome simbolico; per farlo dobbiamo definire, all'inizio del programma, mediante l'istruzione define un identifica­tore di costante in corrispondenza del valore desiderato.


#define BASE 3


Grazie a questa direttiva potremo utilizzare, all'interno del program­ma, BASE al posto del valore intero 3.

La stessa definizione di costante implica che il suo valore non può essere modificato: BASE può essere utilizzata in un'espressione a patto che su di essa non venga mai effettuato un assegnamento.


Vediamo nel Listato come viene modificato il programma del paragrafo precedente con l'utilizzazione delle costanti.


	#include <iostream.h>

	#define BASE 3
	#define ALTEZZA 7

	/* Calcolo area rettangolo  */

	main(){
	  int area;

	  area = BASE * ALTEZZA;

	  cout << “Base: ” << base << “ Altezza: ”<< altezza;
	  cout << “\nArea: ” << area; 
	}

Il nome di una costante può essere qualsiasi identificatore valido in C++, comunque èuso comune utilizzare esclusivamente caratteri maiuscoli per le costanti e caratteri minuscoli per le variabili per distinguere chiara­mente le une dalle altre. Le costanti BASE e ALTEZZA vengono consi­derate di tipo intero in quanto il loro valore è costituito da numeri senza componente frazionaria.


Invece di utilizzare direttamente i valori, è consigliabile far uso degli identificatori di costante che sono descrittivi e quindi migliorano la leggibilità dei programmi. Inoltre, se ci si rende conto che un certo valore utilizzato più volte deve essere cambiato, nella prima ipotesi, è necessario ricercalo con atten­zione all'interno del testo e modificarlo dov'è il caso, nella seconda ipotesi è sufficiente intervenire sulla sua definizione. Per esempio, per fare in modo che il programma precedente calcoli l'area del rettangolo con base 102 e altezza 34, è sufficiente modificare le linee dov'è presente l'istruzione define.


#define BASE 102

#define ALTEZZA 34


In sintesi, l'uso delle costanti migliora due parametri classici di valu­tazione dei programmi: flessibilità e possibilità di manutenzione.


La define è in realtà una macroistruzione (brevemente, macro) del precompilatore C che offre altre possibilità oltre a quella di definire delle costanti.


Incrementare una variabile


Ogni nuova assegnazione ad una variabile, distrugge un valore precedentemente contenuto nella variabile stessa. Per cui, nel successivo esempio:


...

voto = 3;

...

voto = 6;


la variabile voto varrà 6. E ciò qualunque sia stato il valore precedente.


Per aggiungere uno al valore contenuto in una variabile si deve assegnare alla variabile il valore precedente più uno. Ad esempio, questa istruzione aggiunge uno al contenuto della variabile n:


n = n+1;


Difatti il C calcola per prima cosa il valore dell'espressione posta a destra del segno di uguale, cioè n+1. Se ad esempio n vale 5, n+1 vale 6. Questo valore viene poi assegnato alla variabile indicata a sinistra, cioè alla stessa n. Quindi n, che prima valeva 5, dopo l'esecuzione dell'istruzione vale 6.


Questo si chiama incrementare una variabile, cioè appunto aggiungere un nuovo valore al valore precedente (nel caso esaminato si aggiunge 1). L'operazione opposta (togliere, per esempio, 1 al valore della variabile) è chiamata decrementare la variabile. Ovviamente si può usare lo stesso sistema per compiere qualunque operazione sul contenuto della variabile:


area = area*2; // raddoppia l’area

segmento = segmento/k; // divide il segmento per k


Il linguaggio C++ dispone di un operatore speciale per incrementare una variabile di una unità. Scrivere:


contakm++;


equivale a scrivere:


contakm = contakm+1;


Cioè ad incrementare di una unità il valore della variabile contakm. L'operatore ++ è l'operatore di autoincremento. L'operatore reciproco -- (due simboli meno) decrementa di una unità il valore di una variabile:


altezza--; // riduce l’altezza di 1


L'operatore -- è quindi l'operatore di autodecremento.


Si sono viste, quindi, due tecniche per aggiungere uno al valore contenuto in una variabile:


fogli = fogli+1;

fogli++;


Esiste anche una terza tecnica:


fogli += 1;


La combinazione += è un esempio di operatore di assegnazione. L'istruzione:


km += 1;


si può leggere: aggiungi uno al valore corrente della variabile km. L'operatore += non è limitato ad aggiungere 1 ma somma il valore alla sua destra alla variabile alla sua sinistra. Ad esempio:


km += 37;

k1 += k2;

a += (b/2);


equivalgono rispettivamente a:


km = km+37;

k1 = k1+k2;

a = a+(b/2);


L'operatore += non è l'unico operatore di assegnazione, si possono usare tutti gli operatori aritmetici:


km -= 6; // toglie 6 ai km percorsi

lato *= 2; // moltiplica il lato per 2

volume /= 3; // divide il volume per 3

...


Nel seguito di questi appunti si converrà di utilizzare:

 


Pre e post-incremento



Per aggiungere uno alla variabile z si può scrivere in due modi:


z++;

++z;


cioè mettere l'operatore ++ prima o dopo del nome della variabile.


In generale, le due forme sono equivalenti. La differenza importa solo quando si scrive una espressione che contiene z++ o ++z.

Scrivendo z++, il valore di z viene prima usato poi incrementato:


int x,z; // due variabili intere

z = 4; // z vale 4

x = z++; // anche x vale 4 ma z vale 5


Difatti, prima il valore di z (4) è stato assegnato ad x, poi il valore di z è stato incrementato a 5.

Scrivendo ++z, il valore di z viene prima incrementato e poi usato:


int x,z; // due variabili intere

z = 4; // z vale 4

x = ++z; // ora x vale 5 come z


Difatti, prima il valore di z (4) è stato incrementato a 5, poi il nuovo valore di z (5) è stato assegnato ad x.


Immissione ed emissione di dati



Il programma scritto non calcola l'area di un qualsiasi rettangolo ma soltanto di quello che ha per base 3 e per altezza 7, supponiamo centimetri.


Per esempio, per trovare l'area di un rettangolo di base 57 e altezza 20 si deve intervenire sul programma stesso, scrivendo


#define BASE 57

#define ALTEZZA 20


Oppure nel caso della versione del programma dove non si sono utilizzate le costanti ma le variabili, dovremmo scrivere


base = 57;

altezza = 20:


Dopo aver effettuato nuovamente la compilazione, la successiva esecu­zione restituirà 1140, cioè l'area del rettangolo in centimetri quadri.


Per rendere il programma più generale, si deve permettere a chi lo sta utilizzando di immettere i valori della base e dell'altezza; in questo modo l'algoritmo calcolerà l'area di un qualsiasi rettangolo.


cin >> base;


L'esecuzione di questa istruzione fa sì che il sistema attenda l'immis­sione di un dato da parte dell'utente e che lo vada a conservare nella variabile specificata.


In questa istruzione viene utilizzato il canale di input cin e l’operatore di estrazione >>. Anche in questo caso potremmo interpretare l’istruzione come: estrai dal canale di input un dato e conservalo nella variabile specificata. Come già specificato in precedenza la definizione del canale di input si trova, come quella del canale di output, nella libreria iostream.


Durante l'esecuzione di un programma può essere richiesta all'utente l'immissione di più informazioni, perciò è opportuno visualizzare delle frasi esplicative; a tale scopo facciamo precedere le istruzioni di input da opportuni messaggi chiarificatori.


cout << "Valore base: ";

cin >> base;


Quello che apparirà all'utente in fase di esecuzione del programma sarà


Valore base: _


In questo istante si attende che nel canale di input sia disponibile un valore da estrarre. Se l'utente digita 15 seguito da <Invio>


Valore base: 15


questo dato verrà assegnato alla variabile base


Analogamente possiamo modificare il programma per l'immissione dell'altezza e magari aggiungere un'intestazione che spieghi all'utente cosa fa il programma, come nel listato seguente:



	#include <iostream.h>

	// Calcolo area rettangolo  

	main(){
	  int base,altezza,area;

	  cout << "Calcolo AREA RETTANGOLO \n \n";
	  cout << "Valore base: "; 
	  cin >> base;
	  cout << “\nValore altezza: ”; 
	  cin >> altezza;
	  area = base*altezza;

	  cout << “\nBase: ” << base << “ Altezza: ” << altezza; 
	  cout << “\nArea: ” << area;  
	}

Vediamo l'esecuzione del programma nell'ipotesi che l'utente inserisca i valori 10 e 13.



	Calcolo AREA RETTANGOLO	
	Valore base: 10 
	Valore altezza: 13 
	Base: 10 Altezza: 13 

	Area: 130

Notare l’uso del newline per controllare il modo in cui il programma visualizzerà i suoi risultati. I due \n della prima cout, per esempio, servono: il primo per passare ad una nuova linea, il secondo per lasciare una linea vuota.


Con una sola istruzione di input è possibile acquisire più di un valore, per cui i due input dell’esempio precedente, avrebbero potuto essere sostituiti da:


cout << “Introdurre Base e Altezza separati da uno spazio\n”;

cin >> base >> altezza;


In questo caso, quando il programma viene eseguito, alla richiesta di input si risponderà con due numeri (che saranno assegnati rispettivamente a base e ad altezza), separati da uno spazio

 

Istruzione if


Quando si desidera eseguire un'istruzione al presentarsi di una certa condizione, si utilizza l'istruzione if.


Per esempio, se si vuole visualizzare il messaggio “il valore attuale di i è minore di 100” solamente nel caso in cui il valore della variabile intera i è minore di 100, si scrive:


if(i<100) cout << "\n il valore attuale di i è minore di 100";


La sintassi dell'istruzione if è:


if(espressione)

istruzione


dove la valutazione di espressione controlla l'esecuzione di istruzio­ne: se espressione è vera viene eseguita istruzione.


Nell'esempio seguente il programma richiede un numero all'utente e, se tale numero è minore di 100, visualizza un messaggio.



	#include <iostream.h>

	// Esempio utilizzo if 

	main(){
	  int i;

	  cin >> i;
	  if (i<100)
	    cout << "\n minore di 100"; 
	}

L' espressione i<100 è la condizione logica che controlla l'istruzione di stampa e pertanto la sua valutazione potrà restituire soltanto uno dei due valori booleani vero o falso che in C corrispondono rispettivamente ai valori interi uno e zero.È appunto per tale ragione che l'assegnamento a=i<100, è del tutto lecito. Viene infatti valutata l'espressione logica i<100, che restituisce 1 (vero) se i è minore di 100 e 0 (falso) se i è maggiore uguale a 100: il risultato è dunque un numero intero che viene assegnato alla variabile a. Il C++ aggiunge il tipo booleano, che può assumere i valori true o false che non corrispondono ai valori interi innanzi specificati, e che verrà trattato successivamente.


L'operatore != corrisponde a diverso da, per cui l'espressione a!=0 significa: il valore di a è diverso da zero.


Chiedersi se il valore di a è diverso da zero è lo stesso che chiedersi se il valore di a è vero, il che, in C++, corrisponde al controllo eseguito per default (effettuato in mancanza di differenti indicazioni), per cui avremmo anche potuto scrivere


cin >> i;

a = i<100;

if (a)

cout << "\n minore di 100";


La sintassi completa dell'istruzione i f è la seguente:


if(espressione)

istruzione1

[else

istruzione2]


dove la valutazione di espressione controlla l'esecuzione di istruzione1 e istruzione2: se espressione è vera viene eseguita istruzione1, se è falsa viene eseguita istruzione2.


Nell'esempio anteriore è stato omesso il ramo else: il fatto è del tutto legittimo in quanto esso è opzionale, come evidenziato dalle parentesi quadre presenti nella forma sintattica completa.


La tabella seguente mostra gli operatori utilizzabili nell'istruzione if :


Operatore

Esempio

Risultato

!

!a

(NOT logico) 1 se a è 0, altrimenti 0

<

a<b

1 se a<b, altrimenti 0

<=

a<=b

1 se a<=b, altrimenti 0

>

a>b

1 se a>b, altrimenti 0

>=

a>=b

1 se a>=b, altrimenti 0

==

a==b

1 se a è uguale a b, altrimenti 0

!=

a!=b

1 se a non è uguale a b, altrimenti 0

&&

a&&b

(AND logico) 1 se a e b sono veri, altrimenti 0

||

a||b

(OR logico)1 se a è vero, (b non è valutato), 1 se b è vero, altrimenti 0


È opportuno notare che, nel linguaggio C++, il confronto dell’eguaglianza fra i valori di due variabili viene effettuato utilizzando il doppio segno ==. Si confrontino i seguenti due frammenti:


Programma A

Programma B



if (a==b)

If (a=b)

cout << "Sono uguali\n";

cout << "Valore non zero\n";


Il programma A confronta il contenuto della variabile a ed il contenuto della variabile b: se sono uguali stampa la frase specificata.

Il programma B assegna ad a il valore attualmente contenuto in b e verifica se è diverso da zero: in tal caso stampa la frase specificata.


Una ulteriore osservazione va fatta a proposito degli operatori logici ! (NOT logico), && (AND logico) e || (OR logico) che vengono usati per mettere assieme più condizioni. Es.


if (a>5 && a<10)

if (a<2 || a>10)

cout << “a compreso fra 5 e 10”;

cout << “a può essere <2 oppure >10”;


 

 

Istruzioni composte


L'istruzione composta, detta anche blocco, è costituita da un insieme di istruzioni inserite tra parentesi graffe che il compilatore tratta come se fosse un'istruzione unica.


Un'istruzione composta può essere scritta nel programma dovunque possa comparire un'istruzione semplice. Si noti la differenza di esecuzioni dei due frammenti di programma seguenti:


Programma A

Programma B



if (a>100)

if (a>100) {

cout << "Prima frase \n";

cout << "Prima frase \n";

cout << "Seconda frase \n";

cout << "Seconda frase \n";


};


Il programma A visualizzerà "Prima frase" solo se a è maggiore di 100, "Seconda frase" verrà visualizzato in ogni caso: la sua visualizzazione prescinde infatti dalla condizione.

Il programma B, qualora a non risulti maggiore di 100, non visualizzarà alcuna frase: le due cout infatti sono raggruppate in un blocco la cui esecuzione è vincolata dal verificarsi della condizione.


Un blocco può comprendere anche una sola istruzione. Ciò può essere utile per aumentare la chiarezza dei programmi: l’istruzione compresa in una if può essere opportuno racchiuderla in un blocco anche se è una sola. In tal modo risulterà più evidente la dipendenza dell’esecuzione della istruzione dalla condizione.

 

l’operatore ?



L’operatore “?” ha la seguente sintassi:


espr1 ? espr2 : espr3


Se espr1 è vera restituisce espr2 altrimenti restituisce espr3.

Si può utilizzare tale operatore per assegnare, condizionatamente, un valore ad una variabile. In questo modo può rendere un frammento di programma meno dispersivo:


Programma A

Programma B



if (a>100)

sconto=(a>100 ? 10 : 5);

sconto=10;


else


sconto=5;



Cicli e istruzione while


Le strutture cicliche assumono nella scrittura dei programmi un ruolo fondamentale, non fosse altro per il fatto che, utilizzando tali strutture, si può istruire l’eleboratore affinché esegua azioni ripetitive su insiemi di dati diversi: il che è, tutto sommato, il ruolo fondamentale dei sistemi di elaborazione.

È in ragione delle suddette considerazioni che i linguaggi di programmazione mettono a disposizione del programmatore vari tipi di cicli in modo da adattarsi più facilmente alle varie esigenze di scrittura dei programmi. La prima struttura che prendiamo in considerazione è il ciclo while (ciclo iterativo con controllo in testa):


while(esp)

istruzione


Viene verificato che esp sia vera, nel qual caso viene eseguita istruzione. Il ciclo si ripete fintantoché esp risulta essere vera.


Naturalmente, per quanto osservato prima, istruzione può essere un blocco e, anche in questo caso, può essere utile racchiudere l’istruzione in un blocco anche se è una sola.


Scriviamo, a titolo di esempio di uso del ciclo while, un frammento di programma che calcola la somma di una serie di valori positivi immessi dall'utente:



	...
	somma = 0;
	cout << "\n Inserisci un intero positivo:";   
	cin >> numero;  
	while(numero){	
	  somma += numero; 
	  cout << "\n Inserisci un intero positivo:"; 
	  cin >> numero; 
	}					

In questo caso il controllo all’inizio del ciclo garantisce la fine della elaborazione non appena la variabile numero assume valore zero: il ciclo viene ripetuto mentre numero è diverso da zero. L’input, fuori ciclo, del primo numero da elaborare permette di impostare la condizione di controllo sul ciclo stesso. Il totalizzatore somma cumula tutti i valori provenienti da input.



Cicli e istruzione for


L’istruzione for viene utilizzata tradizionalmente per codificare cicli a contatore: istruzioni cicliche cioè che devono essere ripetute un numero definito di volte. Il formato del costrutto for è il seguente:


for(esp1; esp2; esp3)

istruzione


Si faccia attenzione ai punti e virgola posti tra parentesi. Il ciclo inizia con l'esecuzione di esp1 (inizializzazione del ciclo) la quale non verrà più eseguita. Quindi viene esaminata esp2 (condizione di controllo del ciclo). Se esp2 risulta vera, viene eseguita istruzione, altrimenti il ciclo non viene percorso neppure una volta. Successivamente viene eseguita esp3 (aggiornamento) e di nuovo valutata esp2 che se risulta essere vera dà luogo ad una nuova esecuzione di istruzione. Il processo si ripete finché esp3 risulta essere falsa.


Se supponiamo di voler ottenere la somma di tre numeri interi immessi dall'utente, si può scrivere:



	...
	somma = 0; 
	for(i = 1; i <= 3; i++) { 
	  cin >> numero; 
	  somma += numero;
	}

Il programma per prima cosa assegna il valore 1 alla variabile i (la prima espressione del for), si controlla se il valore di i è non superiore a 3 (la seconda espressione) e poiché l’espressione risulta vera verranno eseguite le istruzioni inserite nel ciclo (l’input di numero e l’aggiornamento di somma). Terminate le istruzioni che compongono il ciclo si esegue l’aggiornamento di i così come risulta dalla terza espressione contenuta nel for, si ripete il controllo contenuto nella seconda espressione e si continua come prima finché il valore di i non rende falsa la condizione.


Questo modo di agire del ciclo for è quello comune a tutti i cicli di questo tipo messi a disposizione dai compilatori di diversi linguaggi di programmazione. Il linguaggio C++ mette a disposizione delle opzioni che espandono abbondantemente le potenzialità del for generalizzandolo in maniera tale da comprendere, per esempio, come caso particolare il ciclo while. Il frammento di programma per la somma di una serie di numeri positivi, scritto in precedenza, potrebbe, per esempio, essere riscritto:



	...
	cout << "\n Inserisci un intero positivo:"; 
	cin >> numero; 
	for(somma=0;numero;){
	  somma += numero;  
	  cout << "\n Inserisci un intero positivo:";
	  cin >> numero;
	}					

Il ciclo esegue l’azzeramento di somma (che verrà eseguito una sola volta) e subito dopo il controllo se il valore di numero è diverso da zero e, in questo caso, verranno eseguite le istruzioni del ciclo. Terminate le istruzioni, poiché manca la terza espressione del for, viene ripetuto il controllo su numero.


L’inizializzazione di somma avrebbe potuto essere svolta fuori dalla for: in tal caso sarebbe mancata anche la prima espressione.


Poiché, nel linguaggio C, ogni ciclo while può essere codificato utilizzando un ciclo for e viceversa, è bene tenere presente che la scelta del tipo di codifica da effettuare va sempre fatta in modo da ottenere la massima chiarezza e leggibilità del programma.


Cicli e istruzione do-while


L'uso della istruzione while prevede il test sulla condizione all'inizio del ciclo stesso. Ciò vuol dire che se, per esempio, la condizione dovesse risultare falsa, le istruzioni facenti parte del ciclo verrebbero saltate e non verrebbero eseguite nemmeno una volta.


Quando l'istruzione compresa nel ciclo deve essere comunque eseguita almeno una volta, è più comodo utilizzare il costrutto:


do

istruzione

while(espr);


In questo caso viene eseguita istruzione e successivamente controllato se espr risulta vera, nel qual caso il ciclo viene ripetuto.

Come sempre l'iterazione può comprendere una istruzione composta.


È bene precisare che in un blocco for, while o do...while, così come nel blocco if, può essere presente un numero qualsiasi di istruzioni di ogni tipo ivi compresi altri blocchi for, while o do...while. I cicli possono cioè essere annidati.

TORNA INDIETRO