Corso sul Linguaggio C ++

Transcript

Corso sul Linguaggio C ++
GIOVANNI CALABRESE
Corsi Integrativi di Informatica
Corso sul Linguaggio C
++
!2
CORSI INTEGRATIVI DI INFORMATICA
Corso sul Linguaggio C++ Procedurale
(ediz. 2010)
ITIS “Leonardo da Vinci”
RIMINI
Questo testo è stato creato appositamente per il corso di approfondimento sul linguaggio C++
tenuto da me presso l’ITC Fraccacreta di San Severo (FG), con l’obiettivo di preparare gli
alunni per le olimpiadi dell’informatica.
La bibliografia a cui si fa riferimento è quella riportata nell’appendice 9. Appendici e Link
(pag. 153).
Si tratta di un corso intensivo che presuppone la conoscenza delle basi della programmazione
e che mira soprattutto alla comprensione delle caratteristiche del linguaggio. Chi non ha mai
studiato informatica e programmazione è opportuno che integri con un testo base sull’argomento.
Per acquisire un livello di padronanza nell’uso del linguaggio C sufficiente ad affrontare i
problemi delle selezioni per le olimpiadi di informatica è necessario esercitarsi a lungo, svolgendo, possibilmente, tutti gli esercizi presenti nel testo, sia gli esempi svolti che quelli proposti alla fine di ogni capitolo.
Per la realizzazione pratica dei programmi proposti in questo corso si fa riferimento all’ambiente di sviluppo Dev-C++ distribuito con licenza GNU sul sito:
http://www.bloodshed.net/devcpp.html.
© E’ vietata la riproduzione con qualsiasi mezzo di questo testo senza il permesso dell’autore.
!1
Sommario
!i
1.FONDAMENTI DEL LINGUAGGIO C ..............................................................2
1.1.Caratteristiche e storia del linguaggio C.............................................................2
1.2.Differenze principali tra C e C++ .......................................................................3
1.3.Installazione del Dev-C++ ..................................................................................3
1.4.Gli elementi di un programma C++....................................................................4
1.5.Dal codice sorgente al codice eseguibile ............................................................5
1.6.le direttive al preprocessore ..............................................................................10
1.7.Le funzioni di I/O .............................................................................................11
1.8.Il debug dei programmi con Dev C e Dev Pas .................................................11
Note per l’esecuzione del debugger ........................................................................................................13
Note per la versione 4.9.9.2 ....................................................................................................................13
2.TIPI DI DATI, VARIABILI E COSTANTI, LE ESPRESSIONI .........................14
2.1.Calcolo dell’area di un rettangolo ....................................................................14
2.2.Definizione di variabili .....................................................................................16
2.3.Costanti .............................................................................................................18
2.4.I tipi di dati e le operazioni permesse ...............................................................19
Il tipo int..................................................................................................................................................20
Il tipo char ...............................................................................................................................................21
I tipi float e double ..................................................................................................................................21
Il tipo bool ..............................................................................................................................................21
L’operatore speciale sizeof......................................................................................................................22
2.5.Le espressioni ...................................................................................................22
Gli operatori di assegnamento ................................................................................................................23
Operatori aritmetici .................................................................................................................................24
Operatori relazionali ...............................................................................................................................25
Operatori logici .......................................................................................................................................25
Operatori sui bit ......................................................................................................................................26
Regole di valutazione di un’espressione .................................................................................................27
Operatori speciali ....................................................................................................................................28
Riassunto degli operatori del linguaggio C++ ........................................................................................30
2.6.La conversione di tipo ......................................................................................32
2.7.Le enumerazioni ...............................................................................................34
2.8.Esercizi .............................................................................................................35
Risposte esercizi ...............................................................................................................................36
3.LE ISTRUZIONI E LE STRUTTURE DI CONTROLLO ..................................38
3.1.La programmazione strutturata .........................................................................38
3.2.Le istruzioni semplici .......................................................................................40
3.3.La sequenza ......................................................................................................41
Area di validità delle variabili ..........................................................................................................42
Ciclo di vita delle variabili ...............................................................................................................42
3.4.La Selezione .....................................................................................................43
Problema: equazione di primo grado ......................................................................................................43
3.5.Selezione multipla ............................................................................................44
Problema: una semplice calcolatrice.......................................................................................................45
3.6.I cicli
46
Istruzioni do e while .........................................................................................................................46
Istruzione for ....................................................................................................................................47
Problema numeri primi ....................................................................................................................49
3.7.Documentazione ...............................................................................................49
3.8.Esercizi .............................................................................................................50
Solo selezione...................................................................................................................................51
!ii
Cicli ..................................................................................................................................................52
Doppio ciclo .....................................................................................................................................55
Risposte esercizi ...............................................................................................................................55
4.I SOTTOPROGRAMMI ...................................................................................58
4.1.Le funzioni ........................................................................................................59
Problema scrivere una funzione per calcolare la potenza intera di un numero qualsiasi .................60
4.2.Il passaggio dei parametri .................................................................................61
Problema: scrivere un sottoprogramma per scambiare il contenuto di due variabili .......................62
4.3.I prototipi delle funzioni ...................................................................................63
4.4.Le principali funzioni presenti nelle librerie standard del linguaggio C ..........63
4.5.Meccanismo di esecuzione di un sottoprogramma e funzioni inline................66
4.6.Le variabili static ..............................................................................................69
4.7.Funzioni ricorsive .............................................................................................70
Problema: scrivere una funzione per il calcolo del fattoriale di un numero. ...................................71
4.8.Esercizi .............................................................................................................71
Ricorsione ........................................................................................................................................72
Risposte esercizi ...............................................................................................................................73
5.VETTORI, STRINGHE E PUNTATORI ...........................................................74
5.1.Cosa sono i vettori ............................................................................................74
5.2.A cosa servono i vettori ....................................................................................76
Problema: Far leggere una serie di numeri e visualizzare solo quelli superiori alla media .............77
5.3.Caricamento di un vettore con numeri a caso...................................................77
5.4.Ordinamento di un vettore ................................................................................78
Ordinamento per selezione ...............................................................................................................79
Ordinamento per inserzione .............................................................................................................80
Bubble sort .......................................................................................................................................81
Quick sort .........................................................................................................................................81
5.5.La ricerca in un vettore .....................................................................................82
5.6.Le stringhe di caratteri ......................................................................................83
Problema: Dato un numero di massimo tre cifre trasformarlo in lettere..........................................86
5.7.Le funzioni printf, scanf, puts e gets ................................................................87
printf .................................................................................................................................................88
scanf .................................................................................................................................................89
Input e output di stringhe di caratteri ...............................................................................................90
Problema: trasformare tutti i caratteri di una frase in maiuscolo .....................................................90
5.8.I puntatori .........................................................................................................91
5.9.Puntatori e vettori. Operazioni sui puntatori ....................................................93
Problema: Sostituire in una frase tutte le occorrenze di una parola con un'altra parola data in input.94
5.10.Sottoprogrammi, vettori e puntatori ...............................................................94
Problema: Assegnato nome e cognome generare i primi 6 caratteri del codice fiscale ...................95
5.11.Tipi particolari di puntatori .............................................................................96
Puntatori e funzioni .................................................................................................................................96
6. Esercizi.........................................................................................................................98
Programmi con i vettori .................................................................................................................100
Puntatori .........................................................................................................................................102
Risposte esercizi .............................................................................................................................102
6.STRUTTURE, UNION, MATRICI, TABELLE E L’ALLOCAZIONE DINAMICA
DELLA MEMORIA ........................................................................................104
6.1.Strutture ..........................................................................................................104
6.2.Le union ..........................................................................................................106
!iii
Problema: rappresentazione interna di una variabile .....................................................................106
6.3.Le matrici e le tabelle .....................................................................................106
Matrici ............................................................................................................................................107
Problema: Scrivere un programma per caricare due matrici n x n, calcolarne il prodotto righe per colonne
e visualizzare la matrice risultato. ..................................................................................................108
6.4.Allocazione dinamica della memoria .............................................................109
Problema: Gestione di una pila. ............................................................................................................110
6.5.Assegnare pseudonimi ai tipi di dati ...............................................................111
6.6.Esercizi ...........................................................................................................112
Programmi con le matrici ...............................................................................................................112
7.I FILE SU DISCO ..........................................................................................114
7.1.Input output in generale ..................................................................................114
7.2.I file su disco ...................................................................................................115
Esempio 1 copiare il contenuto di un file in un altro file. ..............................................................117
Esempio2 – Stringhe strane. Problema della selezione regionale 2002. ........................................118
8.RACCOLTA TEST DELLE OLIMPIADI INFORMATICA (SOLO TEST LINGUAGGIO C) ...........................................................................................................120
8.1.Selezione scolastica ........................................................................................121
Anno 2008 (test somministrato il 23/11/2007) .....................................................................................121
Anno 2007 (test somministrato il 16/11/2006) .....................................................................................123
Anno 2006 (test somministrato il 18/11/2005) .....................................................................................124
Anno 2005 ............................................................................................................................................127
Anno 2004.............................................................................................................................................130
8.2.Selezione regionale .........................................................................................133
Prove regionali 2001 – il cassiere Camillo (CAM) .......................................................................133
La biblioteca degli smemorati (BIB) olimpiade regionale 2001 ....................................................134
Lo struzzo Simone (SIM) – olimpiade 2001 ..................................................................................134
Foto Stellare – olimpiadi 2004 ......................................................................................................135
La dieta di Poldo – olimpiadi 2004 ................................................................................................136
Giardinaggio – olimpiade 2004 ......................................................................................................137
Le pesate di bilancino (bilancino) olimpiade – 2006 .....................................................................138
Teste di serie (serie) – olimpiade 2006...........................................................................................138
Ritrovo a Brambillia (brambillia) – olimpiade 2006......................................................................139
Mappa antica – olimpiadi 2008 ......................................................................................................140
8.3.Soluzioni delle selezioni scolastiche ..............................................................141
Test 2008 ........................................................................................................................................141
Test 2007 ........................................................................................................................................142
Test 2006 ........................................................................................................................................142
Test 2005 ........................................................................................................................................142
Test 2004 ........................................................................................................................................142
8.4.Soluzione di alcuni problemi delle selezioni regionali ...................................143
Cassiere Camillo – 2001 ................................................................................................................143
Dieta di Poldo – olimpiadi 2004 ....................................................................................................143
Testa di serie – olimpiadi 2006 ......................................................................................................144
Mappa antica – olimpiadi 2008 ......................................................................................................145
9.APPENDICI E LINK .....................................................................................147
9.1.Conclusioni .....................................................................................................147
9.2.Come approfondire. ........................................................................................148
Libri ......................................................................................................................................................148
Il DEV-C++ ...........................................................................................................................................148
Olimpiadi dell’informatica ...................................................................................................................149
Siti per programmatori ..........................................................................................................................149
Guide on line .........................................................................................................................................149
Link per documentazione......................................................................................................................149
!iv
9.3.Tabelle presenti nel testo ................................................................................149
!v
Corso sul Linguaggio C++ Edizione 2010
1
Capitolo
!1
Corso sul Linguaggio C++ Edizione 2010
1.Fondamenti del linguaggio C
Caratteristiche del linguaggio, creazione dei primi programmi .
1.1.Caratteristiche e storia del linguaggio 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. Successivamente 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 linguaggi. 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.
Le principali caratteristiche del linguaggio C e C++ sono:
- Si tratta di un linguaggio general purpose, ovvero può essere utilizzato per realizzare
programmi di natura diversa (dai sistemi operativi, ai programmi gestionali e ai videogiochi)
- Produce dei programmi efficienti. E’ stato progettato per scrivere più facilmente i programmi che costituiscono un sistema operativo i quali devono essere molto efficienti.
Normalmente, prima della creazione del linguaggio C, i sistemi operativi venivano scritti
in Assembler. Il linguaggio C è un linguaggio di alto livello (più vicino al linguaggio dell’uomo) che però mantiene anche delle caratteristiche tipiche dei linguaggi di basso livello (più vicini al linguaggio della macchina e quindi più scomodi da utilizzare per il programmatore).
- Supporta sia il paradigma procedurale che il paradigma della programmazione orientata agli oggetti. Con il paradigma procedurale il programma consiste in una serie di
istruzioni che dicono al computer come acquisire i dati in ingresso e produrre i risultati
finali, mentre con il paradigma orientato agli oggetti il programma è costituito da una
serie di oggetti software ognuno di quali ha determinate caratteristiche, il programmatore
mette insieme e/o costruisce questi oggetti.
!2
Corso sul Linguaggio C++ Edizione 2010
1.2.Differenze principali tra C e C++
Come detto il linguaggio C++ è un’estensione del linguaggio C e quindi tutti i programmi C
possono essere compilati da un compilatore C++
Il principale miglioramento del linguaggio C++ rispetto al linguaggio C è stata l’introduzione
dei costrutti necessari per realizzare programmi orientati agli oggetti. Nel seguito noi non ci
occuperemo della programmazione ad oggetti ma solo di quella procedurale per la quale le
differenze tra C e C++ sono limitate, eccone alcune:
- I commenti. Con il linguaggio C i commenti vanno racchiusi tra i simboli /* ……*/, nel
linguaggio C++ è stato introdotto anche il simbolo // che indica al compilatore che tutto
quello che segue nella riga è un commento;
- Dichiarazioni all’interno dei blocchi. Con il C++ sono consentite, con il C no.
- Nuovi nomi di tipi. Sono stati introdotti nuovi nomi di tipi che semplificano la notazione.
- E’ stato introdotto lo specificatore const.
- Più funzioni possono utilizzare lo stesso nome, per distinguerle basta che abbiano un
numero o tipo di parametri diverso (overloading di funzioni).
- Si possono richiamare le funzioni con un numero di parametri inferiore a quello dichiarato, i parametri non passati vengono sostituiti con valori standard
- Sono stati introdotti gli operatori new e delete per il controllo dell’allocazione dinamica
della memoria.
1.3.Installazione del Dev-C++
Il linguaggio C è un linguaggio compilato, questo significa che dopo aver scritto il programma sorgente, per poterlo eseguire bisogna prima compilarlo, ovvero tradurlo in linguaggio
macchina. Il programma risultante dopo questa traduzione è detto programma oggetto. La traduzione viene fatta da un altro programma che si chiama compilatore. Per poter scrivere ed
eseguire i programmi in linguaggio C bisogna procurarsi un compilatore C. Sul server del laboratorio è presente l’ambiente di sviluppo Dev C++ versione 4.01 che comprende un compilatore C++ che è open source e distribuito con licenza GNU ed è quindi liberamente scaricabile e utilizzabile nel rispetto della licenza. Per gli aggiornamenti si può visitare il sito del produttore: http://www.bloodshed.net/c/index.html. Attualmente è disponibile anche una versione
più recente, la versione 4.9.9.2, (presente anch’essa sul server nella cartella “Aggiornamenti”)
ma, sebbene sia più comoda da utilizzare, è ancora una versione beta ed è diversa da quella
ufficialmente utilizzata per le olimpiadi dell’informatica.
Per installare il compilatore e il debugger (programma per facilitare la correzione degli errori)
presenti sul server (insieme a molto altrro materiale) all’indirizzo \\192.168.2.198\CorsoCPP\,
bisogna seguire le seguenti istruzioni.
1)
2)
3)
4)
5)
Aprire la cartella DevCPP e Copiare la cartella C++ che si trova all’interno sul proprio computer;
Decomprimere il file “devcpp4.zip” ed eseguire il file “setup.exe”; ciò installerà la versione 4.0 del
Dev-C++.
Sostituire il file “DevCpp.exe” contenuto nella directory di installazione del Dev-C++ (ad esempio “C:
\Dev-C++”) con il file “DevCpp.exe” contenuto dentro l’archivio devcpp401.zip.
Decomprimere il file insight5_win32.zip (che contiene il debugger per l’ambiente) e che si trova nella
cartella Debugger; nell’archivio sono contenute due cartelle: “bin” e “share”. Copiare la directory
“share” nella directory di installazione del Dev-C++ (ad esempio “C:\Dev-C++”), e copiare i file contenuti nella cartella “bin” nella cartella “bin” della directory di installazione del Dev-C++ (ad esempio
C:\Dev-C++\bin)
A questo punto avete installato l’ambiente di sviluppo. Conviene crearsi una cartella personale sul disco rigido del computer dove mettere tutti i programmi che scriverete e impostarla come cartella di
default per l’ambiente di sviluppo. Per farlo prima create la cartella (per esempio la cartella c:\<vostro-
!3
Corso sul Linguaggio C++ Edizione 2010
nome>\cpp); poi lanciate l’ambiente di sviluppo da start programmi!DevC++!Dev-C++; rispondete si alla richiesta se abbinare le estensioni .cpp, .dev ecc. al Dev-C++; dopo aver avviato l’ambiente di
sviluppo fate click su Options!Environment Options sulla barra dei menù e nella scheda Preferences,
impostate la Default directory con il percorso della directory che avete creato per i programmi C++
(vedi figura che segue).
!
1.4.Gli elementi di un programma C++
Un programma C++ è costituito dai seguenti elementi:
Direttive al preprocessore
Dichiarazioni di variabili globali, funzioni e prototipi di funzioni
Programma principale (funzione main)
!
Funzione 1
Funzione N
!4
Corso sul Linguaggio C++ Edizione 2010
Tutti gli elementi sono facoltativi esclusa la funzione main (il programma principale) che
deve sempre esserci.
Le regole con cui deve essere scritto un programma o un’istruzione di un programma sono
dette regole sintattiche in analogia per le regole del nostro linguaggio naturale. Per descrivere
queste regole si utilizzano spesso, nei manuali dei linguaggi di programmazione, i grafi sintattici che rappresentano tutti i modi in cui si possono costruire le frasi valide del linguaggio. Per
esempio, utilizzando un grafo sintattico per descrivere quanto detto prima, un programma C+
+ deve essere costruito nel seguente modo:
Programma C++
Funzione
main()
!
Direttive al
preprocessore
Funzioni e
Prototipi di
Va r i a b i l i
globali
D i c h i a r azioni altre
funzioni
Il programma Principale (così come qualsiasi funzione) deve avere la seguente struttura:
[<Tipo restituito>] main ([elenco parametri])
{
[istruzione1;]
[istruzione2;]
……..
[istruzione n;]
}
<Tipo restituito> indica il tipo di dati restituito dalla funzione, in mancanza di indicazione si
sottintende int ovvero intero. Una delle istruzione della funzione è normalmente:
return <valore>
che fa terminare la funzione restituendo il valore indicato (se non viene inserita il compilatore
inserisce automaticamente return 0).
Il più semplice programma C è quindi il seguente:
int main() {
return 0
}
Se una funzione non restituisce nessun valore si può anche indicare, come tipo, la parola
chiave void che rappresenta un tipo di dato particolare. Questo è il modo in cui si dichiarano
nel linguaggio C le procedure. Per esempio se il programma principale non deve restituire
nessun valore si può scrivere:
void main(){
}
1.5.Dal codice sorgente al codice eseguibile
Vediamo ora come si realizza praticamente un programma C++. I passi da seguire per creare
un programma eseguibile sono i seguenti:
1. Scrittura del programma sorgente; Apriamo l’ambiente di sviluppo Dev-C++ e scegliamo New Source File dal menù File. Verrà visualizzato il file default.txt che contiene
la base per un qualsiasi programma C. A questo punto scriviamo il programma, per
esempio quello della figura che segue. Alla fine salviamo il file usando la voce Save
!5
Corso sul Linguaggio C++ Edizione 2010
Unit o Save Unita s .. dal menù File. Il programma verrà salvato con il nome che scegliamo e normalmente con l’estensione .cpp (verificare che la cartella sia quella giusta);
2. Compilazione e linking. Un programma scritto in linguaggio C non può essere eseguito così com’è perché il computer capisce solo il linguaggio macchina. Per eseguire un
programma bisogna compilarlo (tradurlo in linguaggio macchina) e unirci i sottoprogrammi standard del linguaggio (operazione di link), dopo queste due operazioni viene
creato un programma in linguaggio macchina eseguibile con estensione .exe, questo secondo programma può essere mandato in esecuzione. Per eseguire la compilazione e il
linking bisogna scegliere Compile dal menù Execute. Se non vengono trovati errori verrà creato il programma eseguibile con lo stesso nome del programma sorgente ma con
estensione “.exe”. Nella scheda Compiler che si trova nel riquadro posto nella parte inferiore della finestra del Dev-C++, vengono visualizzati i messaggi del compilatore. Se
la compilazione è andata a buon fine verrà viaulizzato il messaggio <nome programma> compiled successfully, altrimenti vengono visualizzati gli errori trovati con l’indicazione della riga dove sono stati trovati;
3. Esecuzione. Scegliere Run dal menù Execute. Viene aperta la finestra di esecuzione
dove va l’output del programma e il programma viene eseguito. Al termine la finestra di
esecuzione viene chiusa automaticamente.
Per esempio provate a scrivere il seguente programma:
!6
Corso sul Linguaggio C++ Edizione 2010
!
Vediamo che cosa significa quello che abbiamo scritto. 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. Le istruzioni cout << …. sono 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 output. 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 inseriscono una di seguito all’altra le stringhe specificate.
L’istruzione system("PAUSE") impedisce alla schermata di esecuzione di scomparire senza
darci il tempo di vedere il risultato del nostro programma, questa istruzione manda in esecuzione il comando PAUSE del sistema operativo. Questo comando invia nel canale di output la
stringa “Premere un tasto per continuare …” e aspetta fino a quando non viene premuto un
tasto. Se aprite una finestra di comandi (Start!Programmi!Accessori!Prompt dei comandi) potete provare a scrivere il comando PAUSE e vederne l’effetto. Con la funzione system si
!7
Corso sul Linguaggio C++ Edizione 2010
può mandare in esecuzione qualsiasi comando del sistema operativo o programma. Per esempio:
• system (“CLS”) pulisce la finestra di output (CLS=Clear Screen).
• system(“Color 1F”) imposta il colore blu come sfondo e il colore bianco come primo
piano (il comando generale è color xy dove x e y sono due cifre esadecimali con
x=colore di sfondo e y=colore di primo piano)
Per utilizzare la funzione system nei nostri programmi dobbiamo inserire all’inizio
#include <stdlib.h>
Ogni istruzione deve terminare con un carattere di punto e virgola. Se paragoniamo un programma ad un testo, le istruzioni sono le frasi e ogni istruzione è costituita da una serie di parole dette token separate le une dalle altre da spazi o simboli (per esempio la punteggiatura).
Così come il significato di una frase non cambia in base al numero di spazi tra le parole, anche il numero di spazi inserito tra le parole di una istruzione C++ è irrilevante, mentre cambia
il significato della frase se si inserisce uno spazio tra i caratteri di una parola spezzandola.
Per poter utilizzare cout, come le altre funzioni di entrata/uscita, si deve inserire all'inizio del
testo la direttiva al preprocessore
#include <iostream.h>
che avverte il compilatore di includere i riferimenti alla libreria dei canali standard di input/
output (iostream sta per canali di input/output).
Il C++ è un linguaggio case-sensitive ovvero distingue tra lettere maiuscole e minuscole;
dunque occorre fare attenzione, se si scrive MAIN() o Main() non si fa riferimento a main().
Proviamo a compilare ed eseguire il programma che abbiamo scritto, se non ci sono errori
nella finestra di esecuzione compare la scritta :
abcdefghilmnopqrstuvzPremere un tasto per continuare …
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 (\n è un carattere speciale
che fa andare a capo il cursore sul monitor, si tratta del carattere new line), come nel seguente
listato.
#include <iostream.h>
#include <stdlib.h>
main(){
cout << "abc"
<<
cout << "def"
<<
cout << "ghi"
<<
cout << "lmn"
<<
cout << "opqrs" <<
cout << "tuvz" <<
system(“PAUSE”);
}
“\n”;
“\n”;
“\n”;
“\n”;
“\n”;
“\n”;
Eseguendo il programma si otterrà la visualizzazione delle seguenti stringhe di caratteri
abc
def
ghi
lmn
!8
Corso sul Linguaggio C++ Edizione 2010
opqrs
tuvz
Premere un tasto per continuare ….
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 << “\nabc\ndef”;
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).
Esistono altri caratteri di controllo, tutti vengono indicati con una sequenza che inizia con la
barra rovesciata(\), di seguito vengono riportati quelli che hanno utilizzo più frequente:
Tabella 1. Sequenze di escape
Sequenza
Effetto
\n
porta il cursore all’inizio della riga successiva (ASCII 10 = new line)
\t
porta il cursore al prossimo fermo di tabulazione (ogni fermo di
tabulazione è fissato ad 8 caratteri) (ASCII 9)
\a
(alert) fa un beep
\f
(form feed) nuova pagina (ASCII 12)
\r
(cariage return) ritorno del carrello nella stampa (ASCII 13)
\’
stampa un apice
\”
stampa le virgolette
\\
barra rovesciata
\?
Punto di domanda
\b
(Bakspace) Indietro di un carattere. (ASCII 8)
\<cifreOttali>
Il carattere corrispondente nel codice ASCII al numero ottale
\x<cifreEsadec Il carattere corrispondente nel codice ASCII al numero esadecimale
>
La sequenza costituita dalla barra rovesciata seguita da uno o più caratteri viene detta sequenza di escape e corrisponde ad un solo carattere. Utilizzando una sequenza di escape si può
inserire anche il carattere corrispondente ad un qualsiasi codice ASCII in due modi: utilizzan!9
Corso sul Linguaggio C++ Edizione 2010
do la barra rovesciata (\) seguita dal codice ASCII scritto in ottale oppure la barra rovesciata e
la x (\x) seguita dalle cifre esadecimali del codice ASCII (per esempio \x41 corrisponde al
carattere ‘A’).
Quando si fanno delle modifiche al programma sorgente per provarlo bisogna compilarlo ed
eseguirlo ma attenzione a chiudere l’eventuale finestra di un esecuzione precedente perché, se
è ancora aperta, il programma eseguibile è bloccato e il compilatore non può sostituirlo con
quello nuovo. Purtroppo, il dev-c++ non segnala nessun errore in questo caso, semplicemente
rimanda in esecuzione il vecchio programma.
1.6.le direttive al preprocessore
A differenza di altri linguaggio, la compilazione di un programma in linguaggio C prevede
una prima fase detta precompilazione, svolta da un apposito modulo detto preprocessore. Il
Preprocessore è normalmente incluso nel compilatore. Nella fase di precompilazione il programma viene preparato per la successiva compilazione.
E’ possibile inserire in un programma C delle istruzioni che verranno eseguite dal preprocessore, queste istruzioni sono dette direttive al preprocessore o dichiarative di precompilazione, tutte le direttive al preprocessore hanno la seguente struttura:
#<nome direttiva> <dichiarazione della direttiva>
con i grafi sintattici:
direttive al preprocessore
#
!
nome direttiva
dichiarazione direttiva
Una delle direttive più utilizzate è la direttiva include per esempio:
#include <iostream.h>
oppure
#include “iostream.h”
Questa direttiva dice al preprocessore di inserire nel file sorgente il file “iostream.h” che è un
file che contiene i riferimenti alle funzioni standard di Input e Output. Se si usano le parentesi
angolari (<…>) il preprocessore ricercherà il file nelle cartelle di sistema (che si possono modificare intervenendo nella scheda Directories visualizzata con la voce di menù
Options!Compiler Options), se si usano i doppi apici cercherà prima nella cartella corrente.
Se invece di inserire la direttiva si copiasse il contenuto del file “iostream.h” nel programma
sorgente il risultato della compilazione sarebbe lo stesso.
I file con estensione .h sono file di intestazione e contengono le dichiarazioni necessarie per
richiamare, all’interno del codice sorgente, i sottoprogrammi inclusi in librerie esterne. Molte
librerie di sottoprogrammi sono incluse nell’ambiente di sviluppo e, inoltre, qualsiasi programmatore può creare ulteriori librerie personali. Il programmatore che ha creato la libreria
deve anche creare uno o più file di intestazione che dovranno essere inclusi nei programmi
che utilizzeranno la libreria.
Con l’introduzione nel linguaggio C++ di nuove funzionalità, come i template e i namespace, che non esistevano nel linguaggio C, le librerie standard sono state riscritte. Nei programmi C++, comunque, si possono usare sia le vecchie versioni delle librerie che le nuove. In genere i file da includere per le nuove versioni hanno lo stesso nome dei vecchi con una ‘c’ davanti e senza l’estensione .h. Per esempio <stdio.h> diventa <cstdio> e <stdlib.h> diventa
<cstdlib>. Se si decide di utilizzare le nuove versione delle librerie bisogna anche specificare
!10
Corso sul Linguaggio C++ Edizione 2010
che nel programma si userà il namespace std che è quello in cui sono inclusi tutti i nomi di
funzione e gli identificatori delle librerie standard. Per esempio si può scrivere:
#include <cstdlib>
#include <iostream>
using namespace std;
invece di
#include <stdlib.h>
#include <iostream.h>.
Attenzione, il nuovo file <iostream> richiama al suo interno tutte le librerie standard (quelle
che iniziano con “st”) per cui nella maggior parte dei programmi si può anche includere solo
la libreria <iostream>:
#include <iostream>
using namespace std;
Nel seguito ho utilizzato la vecchia sintassi che è compatibile con tutte le versioni del linguaggio.
1.7.Le funzioni di I/O
Fra le istruzioni più importanti di un programma ci sono quelle di input/output cioè quelle che
servono per far leggere i dati da elaborare (input) e visualizzare i risultati dell’elaborazione
(output). Per ora utilizzeremo due sole istruzioni con sintassi semplificata, l’istruzione cout,
che abbiamo già visto, per l’output e l’istruzione cin per l’input. La sintassi è la seguente:
per l’output
cout
espressione
<<
per l’input
cin
variabile
>>
cin sta per console input e dice al computer mandare i dati provenienti dall’unità di input
standard (normalmente la tastiera) dentro una o più variabili (se ci sono più variabili, durante
l’esecuzione bisogna inserire più dati con un ritorno a capo oppure uno spazio tra uno e
l’altro). Il simbolo >> può essere tradotto con “memorizza in” e dice al computer di prelevare
un dato dalla console di input e memorizzarlo nelle variabile.
1.8.Il debug dei programmi con Dev C e Dev Pas
Dopo aver installato il compilatore C o pascal e il debugger seguendo le note di installazione
riportate sopra, normalmente il compilatore viene impostato automaticamente per generare un
programma eseguibile il più possibile efficiente. Purtroppo per poter eseguire il debug è necessario inserire nel programma eseguibile riferimenti al programma sorgente che aumentano
le dimensioni del file eseguibile e lo rendono meno efficiente. Quando il compilatore viene
installato viene automaticamente impostato per non inserire queste informazioni nel file eseguibile e quindi il debug non funziona!
Per farlo funzionare bisogna seguire la seguente procedura:
!11
Corso sul Linguaggio C++ Edizione 2010
1. Scegliere Options - Compiler options dal menu
!
2. Spuntare la casella "Generate debugging information" dalla scheda "Linker" della finestra delle opzioni del compilatore e fare click su OK
!
3. Compilare il programma (ricompilare se era stato già compilato) ed eseguire il programma facendo click sull'apposita icona della barra degli strumenti oppure sulla voce
del menù Execute oppure con F8.
!
4. Comparirà la finestra del debug con una copia del programma sorgente. Facendo click
su Run (o sull'icona corrispondente della barra degli strumenti !
) il programma si
avvierà, comparirà la finestra del programma (la console per i programmi non windows) e la prima istruzione eseguibile verrà evidenziata nella finestra del debug.
!12
Corso sul Linguaggio C++ Edizione 2010
!
5. Dalla finestra del sorgente è possibile:
inserire e togliere punti di interruzione facendo clik con il mouse a sinistra dell'istruzione corrispondente (un punto di interruzione viene visualizzato con un quadratino
nero); eseguire un'istruzione alla volta facendo click su l’icona Step (!
) della barra degli
strumenti oppure su Next ( !
), la differenza tra le due si nota solo se l’istruzione è
una chiamata ad un sottoprogramma (con Step si passa alla prima istruzione del sottoprogramma, con Next verrà eseguito l’intero sottoprogramma e si passa all’istruzione
successiva); far proseguire il programma fino al prossimo punto di interruzione (!
le variabili locali (!
), visualizzare
), ecc.
Note per l’esecuzione del debugger
Se si vuole eseguire un programma utilizzando il debug bisogna avere le seguenti accortezze:
1. la cartella che contiene il file sorgente deve trovarsi sullo stesso volume dove è installato il dev-pas o il dev-c;
2. prima di eseguire il debug accertarsi di aver compilato il programma con l’opzione
“Generate debugging information” attivabile dal menù Options!Compiler Options;
3. se si utilizzano dei file in input questi devono trovarsi nella cartella BIN contenuta nella cartella di installazione del del C (per es: C:\Dev-C++\Bin).
Note per la versione 4.9.9.2
L’ultima versione del DEV C, presenta dei bug per quanto riguarda i nomi dei file. Se si salva
il programma con nomi di file lunghi che contengono caratteri speciali come spazi e parentesi
tonde, possono verificarsi problemi.
Per esempio se si salva un programma con il nome “Prova programma” e poi si salva nella
stessa cartella un altro programma con nome “Prova programma (1)” quando si manda in esecuzione il secondo parte l’eseguibile del primo invece del secondo.
Si raccomando di usare nomi corti e non contenenti caratteri speciali.
!13
Corso sul Linguaggio C++ Edizione 2010
2
Capitolo
2.Tipi di dati, variabili e costanti, le espressioni
2.1.Calcolo dell’area di un rettangolo
Un qualsiasi programma, in genere, legge dei dati e produce dei risultati. Tutti i dati utilizzati,
sia quelli iniziali che quelli intermedi e finali vengono conservati in memoria. I dati di un
programma si distinguono in due categorie: variabili e costanti. I dati variabili sono quelli che
possono cambiare da un’esecuzione all’altra dello stesso programma o durante una stessa esecuzione, i dati costanti, invece, assumono sempre lo stesso valore ogni volta che si esegue il
programma.
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.
Il programma potrebbe essere il seguente:
#include <iostream.h>
#include <stdlib.h>
// Calcolo area di un rettangolo
int main()
{
int base, altezza; int 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 << "\n\n";
}
system("PAUSE");
return 0;
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
!14
Corso sul Linguaggio C++ Edizione 2010
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.
Subito dopo main() sono presenti le dichiarazioni delle variabili intere necessarie:
int base, altezza; int area;
La parola chiave int specifica che l'identificatore che lo segue si riferisce 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.
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.
L’istruzione cout << "Calcolo AREA RETTANGOLO \n \n"; visualizza su video la stringa di
caratteri "Calcolo AREA RETTANGOLO” seguita da due righe vuote.
Le due istruzioni
cout << "Valore base: ";
cin >> base;
servono per leggere il valore della base. Prima viene visualizzata la frase “Valore base: “, poi
il sistema aspetta che l’operatore batta un numero sulla tastiera e lo trasferisce nella variabile
base.
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, si possono inserire spazi e righe vuote dove si desidera. Non bisogna dimenticare, però, di inserire il carattere ; (punto e virgola) dopo ogni istruzione. 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.
Analogamente la riga successiva serve per far leggere il valore dell’altezza e inserirlo nella
variabile altezza.
L’istruzione
area = base*altezza;
!15
Corso sul Linguaggio C++ Edizione 2010
è un’istruzione di assegnazione. Essa dice al computer di calcolare il valore dell’espressione a
destra dell’uguale e assegnare il risultato alla variabile a sinistra del simbolo =; cioè inserisce
nello spazio di memoria riservato a tale variabile il valore indicato.
L'operatore asterisco effettua l'operazione di prodotto tra la variabile che lo precede e quella
che lo segue, è dunque un operatore binario.
Nel linguaggio C++ è possibile assegnare lo stesso valore a più variabili contemporaneamente. Per esempio
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.
Le ultime istruzioni visualizzano su video i valori delle variabili in input e il risultato.
2.2.Definizione di variabili
Tutte le variabili utilizzate in un programma devono essere preventivamente definite. La definizione di una variabile è un’istruzione che serve per creare la variabile in memoria.
In generale la definizione di variabili ha la seguente forma:
Modificatore della
modalità di memorizzazione
Modificatore
di tipo
Tipo di dato
,
Identificatore
Valore iniziale
=
Opzionalmente si può premettere ad una definizione di variabile la modalità di memorizzazione che indica al computer come e dove memorizzare la variabile.
Le modalità di memorizzazione sono le seguenti:
Modalità
memorizzazione
d i Dichiara al compilatore che l’elemento va memorizzato …..
auto
Nelle celle della memoria centrale dell’elaboratore (è quella
di default)
register
Negli elementi hardware dell’elaboratore che costituiscono la
memoria più veloce. In genere i compilatori cercano di
memorizzare queste variabili nei registri interni della CPU o
nella memoria cache.
extern
È definito in un altro file sorgente
static
Nella memoria centrale ma il valore non viene mai cancellato
durante l’esecuzione del programma
volatile
Nella memoria centrale, ma il valore può essere modificato,
oltre che dal programma anche direttamente dall’hardware.
Questa modalità viene utilizzata in casi particolari come
quando si devono gestire i dati provenienti o da inviare ad un
MODEM o ad altre periferiche.
Per esempio:
!16
Corso sul Linguaggio C++ Edizione 2010
static int a
dice al computer di creare una variabile di tipo intero in uno spazio che non deve essere cancellato quando il sottoprogramma che contiene la definizione termina (normalmente tutte le
variabili di un sottoprogramma vengono cancellate quando il sottoprogramma termina l’esecuzione).
Oltre alla modalità di memorizzazione si può inserire in una definizione di variabile un modificatore di tipo, i principali modificatori di tipo sono i seguenti:
modificatore di tipo
Descrizione
const
Indica al compilatore che il dato definito è un dato costante che
quindi non potrà subire variazione durante l’esecuzione del
programma
signed
Il valore è un numero con il segno
unsigned
Il valore è un numero senza segno
Short
Riduce il numero di byte riservati a contenere il dato
Long
Aumenta il numero di byte riservato a contenere il dato
Per esempio la definizione
short int num;
dichiara una variabile che occupa solo due byte (numeri da -32768 a + 32767);
short unsigned int num;
dichiara una variabile sempre di due byte ma senza segno e quindi i valori possono andare da
0 a 65536
Il tipo di dato indica al sistema la dimensione della variabile e l'insieme delle operazioni che
si possono effettuare su di essa. 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 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 (/). Nel seguito esamineremo i principali tipi di dato.
Ogni variabile deve avere un nome che identifica la variabile all’interno del programma e per
questo viene detto identificatore. Esistono delle regole da rispettare nella costruzione degli
identificatori: devono iniziare con una lettera o con un carattere di sottolineatura _ e possono
contenere solo lettere, cifre e _ (non possono contenere simboli di punteggiature, segni di
operazione e altri caratteri speciali). 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 identificatore non può essere una
parola chiave del linguaggio, né può essere uguale ad un nome di funzione in libreria o scritta
dal programmatore.
!17
Corso sul Linguaggio C++ Edizione 2010
In generale è inoltre bene dare alle variabili dei nomi significativi, in modo che, quando si
debba intervenire a distanza di tempo sullo stesso programma, si possa facilmente ricostruire
l'uso che si è fatto di una certa variabile.
A differenza di altri linguaggi di programmazione, nel linguaggio C, l’istruzione di definizione di una variabile può essere utilizzata anche per inizializzarla ovvero per assegnargli il valore iniziale. Per esempio:
int somma = 0, prod=1;
crea la variabile somma e ci mette dentro il valore 0, poi crea la variabile prod e ci mette 1.
2.3.Costanti
Nel paragrafo 2.1 abbiamo esaminato il programma per calcolare l’area di un rettangolo. Supponiamo ora di voler scrivere un programma per calcolare l’area del cerchio che sappiamo si
calcola con la formula area = πr2, dove π è un numero fisso che corrisponde approssimativamente a 3,14. Quindi per calcolare l’area del cerchio bisogna indicare al computer anche il
valore di π che è un dato costante del problema. Il programma potrebbe essere il seguente:
#include <iostream.h>
#include <stdlib.h>
#define PIGRECO 3.14
// Calcolo area di un cerchio
int main()
{
float raggio, area;
cout << "Calcolo AREA Cerchio \n \n";
cout << "Raggio: "; cin >> raggio;
area = PIGRECO*raggio*raggio;
cout << "\nArea: " << area << "\n\n";
}
system("PAUSE");
return 0;
In questo caso le variabili raggio e area sono state dichiarate di tipo float perché questo tipo
può contenere anche numeri con la virgola, inoltre è stata inserita la direttiva al preprocessore
#define
PIGRECO 3.14
Questo dice al preprocessore che ogni volta che trova la serie di caratteri PIGRECO deve sostituirli con il numero 3.14. In effetti se nel programma sorgente togliamo la direttiva define e
sostituiamo l’istruzione area=PIGRECO*raggio*raggio con
area = 3.14 * raggio * raggio
il programma eseguibile sarebbe esattamente lo stesso.
In pratica una costante è una valore fisso nel programma e noi possiamo indicarlo nelle istruzioni o scrivendo il valore o definendo un nome simbolico che rappresenta il valore.
I valori costanti che si possono inserire in un programma C++ possono essere di vario tipo:
• Numeri decimale interi (per esempio 10, 30, -56, 4545445 …)
• Numeri ottali interi (per esempio 064, 010, … ) iniziano sempre con uno zero e contengono le cifre da 0 a 7;
• Numeri esadecimali interi (0x23F, 0x30, 0xBB …) iniziano sempre con 0x e contengono le cifre da 0 fino a F;
!18
Corso sul Linguaggio C++ Edizione 2010
•
•
•
Numeri decimali con la virgola o in virgola mobile (per esempio 3.14, -2.0, -0.1,
6.567E+7, 0.450123e-3 …). Per rappresentare la virgola si usa il punto;
Un carattere singolo (per esempio ‘a’, ‘B’, ‘7’…), deve essere racchiuso tra due apici;
Una stringa di caratteri (“Mario”, “Buongiorno mondo”, ….), la stringa è un gruppo di
caratteri racchiuso tra virgolette (“); tutte le stringhe terminano con il carattere speciale \0 (codice ascii 0) che viene inserito automaticamente dal compilatore;
Quando un certo valore viene utilizzato in modo ricorrente è opportuno rimpiazzarlo con un
nome simbolico; inoltre spesso conviene definire le costanti per aumentare la leggibilità di un
programma perché in alcuni casi il nome di un dato indica più chiaramente, a chi legge il programma, il significato dell’istruzione. Per esempio se abbiamo codificato le mansioni svolte
dagli impiegati di una azienda con dei numeri e 1 significa operaio, 2=impiegato, 9=dirigente
l’istruzione
mansione=DIRIGENTE
è più chiara di
mansione =9
per sostituire la costante 9 con la parola DIRIGENTE dobbiamo inserire la direttiva
#define DIRIGENTE 9
nel programma prima dell’uso della costante.
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 chiaramente le une dalle altre.
In sintesi, l'uso delle costanti migliora due parametri classici di valutazione dei programmi:
flessibilità e possibilità di manutenzione.
Con il linguaggio C++, oltre alla direttiva define (presente nel linguaggio C) per definire le
costanti si può utilizzare il modificatore di tipo const e quindi si può anche scrivere:
const float PIGRECO=3.14;
2.4.I tipi di dati e le operazioni permesse
Una delle caratteristiche che differenziano il linguaggio C rispetto agli altri linguaggi è la
maggiore disponibilità di tipi di dati e di operatori. Per quanto riguarda i tipi di dati abbiamo
già visto la possibilità di utilizzare i modificatori di tipo e di modalità di memorizzazione che
di fatto amplia la gamma dei tipi disponibili.
Negli esempi che abbiamo visto finora abbiamo utilizzato due tipi di dato, numeri interi (tipo
int) e numeri con la virgola (tipo float). Ogni linguaggio di programmazione mette a disposizione dei programmatori un insieme di tipi di dati che il programmatore può utilizzare come
contenitori per i dati dei suoi programmi.
Nel linguaggio C++ i tipi di dato fondamentali sono:
!19
Corso sul Linguaggio C++ Edizione 2010
void
bool
elementari
char
int
float
Tipi di dato
double
enum
array
strutturati
strutture
union
puntatori
!
Il tipo int
Il tipo int viene utilizzato per memorizzare numeri interi relativi. Il numero viene scritto nella
memoria del computer in binario, i numeri negativi (non ammessi se si utilizza il modificatore
di tipo unsigned) vengono rappresentati con il complemento a 2. A seconda del modificatore
di tipo utilizzato abbiamo:
short int
signed short int
numeri da - 32768 a +32 767, occupa 2 byte,
unsigned short int
Numeri da 0 a 65535 occupa 2 byte
long int
signed long int
numeri da -2147483648 a +2147483647 occupa 4 byte
Unsigned long int
Numero da 0 a 4294967295, 4 byte
int
La dimensione può coincedere con short int o con long int a
seconda dell’implementazione. In genere quelle sotto il
sistema MS-DOS corrispondevano a short int, quelle sotto
Windows come quella che utilizziamo noi (Dev-C++)
corrispondono a long int
Le operazioni permesse sono: la somma (+), la sottrazione (-), il prodotto (*), e la divisione
(/), il modulo o resto della divisione (%), l’assegnazione (=), l’incremento (++) e il decremento (--), oltre alle combinazioni delle quattro operazioni con l’assegnazione (+=, -=, *=, /
=).
!20
Corso sul Linguaggio C++ Edizione 2010
Il tipo char
Una variabile di tipo char può memorizzare un solo carattere. In realtà nella memoria viene
memorizzato il codice ASCII del carattere e quindi un numero intero da 0 a 255. Per questo
motivo una variabile char occupa un solo byte ed è compatibile con il tipo intero. Per questo
tipo di variabili sono definite tutte le operazioni definite per i numeri interi, in più è possibile
assegnare alla variabile anche un singolo carattere, per esempio, visto che il codice ASCII della lettera ‘B’ è 66, le due istruzioni seguenti sono equivalenti::
e
char lett=’B’;
char lett = 66;
Una variabile di tipo char può essere utilizzata anche per contenere numeri interi senza segno
da 0 a 255 oppure numeri interi con segno da -128 a + 127, a seconda se si definisce come
unsigned char o signed char ed è compatibile con i tipi numerici, ma se viene inviata in
output con cout verrà visualizzato sempre il carattere corrispondente al codice ASCII memorizzato e non il numero.
Come detto prima sulle variabili di tipo char sono definite tutte le operazioni definite con il
tipo intero, quindi le quattro operazioni principali (+, -, *, /) ma anche incremento e decremento (++, --), il modulo (%) e le combinazioni delle quattro operazioni con l’assegnazione
(+=, -=. *=, /=). Quindi è corretta sintatticamente un’istruzione del tipo:
lett=lett +2;
Dopo questa operazione, supponendo che la variabile lett sia stata creata con l’istruzione precedente di questo paragrafo, il codice ASCII presente nella variabile viene aumentato di 2 e
quindi la lettera contenuta non sarà più ‘B’ ma ‘D’. Da notare che le costanti di tipo char, ovvero costituite da un solo carattere, si racchiudono tra due apostrofi (‘), mentre le costanti
stringa sono sempre racchiuse utilizzando il doppio apice (“), per esempio ‘A’, ‘k’ sono costanti di tipo char mentre “Mario” è una costante di tipo stringa.
Oltre al tipo char, in molte versioni del linguaggio, è stato inserito anche il tipo wchar_t che
occupa 2 bytes (16 bit) invece di uno e viene utilizzato per memorizzare i caratteri con il codice Unicode invece del codice ASCII. Il codice Unicode permette di rappresentare un numero di caratteri molto maggiore di 255, praticamente tutti i caratteri esistenti nelle lingue del
mondo.
I tipi float e double
I due tipi float e double servono per memorizzare i numeri reali. La rappresentazione interna è quella
binaria virgola mobile. Ogni variabile di tipo float occupa 4 bytes e può contenere numeri fino a 10±38
ma di tutte le cifre del numero solo le sette più significative sono memorizzate esattamente. Il tipo
double occupa 8 bytes, la rappresentazione interna è sempre binario virgola mobile, può memorizzare
numeri fino a 10±308 con esatte le 15 cifre più significative. Per questi tipo non si può utilizzare i modificatori short,long, signed e unsigned, in pratica i numeri vengono memorizzati sempre con il segno e il tipo
float corrisponde a un ipotetico short double, solo per il tipo double si può anche utilizzare il modificatore
long con il DEV-C++, le variabili di tipo long double occupano 12 bytes.
Il fatto che i numeri sono memorizzati in binario virgola mobile permette di memorizzare numeri molto grandi e anche molto piccoli in modo abbastanza preciso e in poco spazio ma crea anche un problema, infatti, i numeri frazionari che in decimale hanno un numero finito di cifre spesso in binario
diventano periodici e quindi con infinite cifre, per questo motivo anche un numero come 0.1 non può
essere memorizzato esattamente in questo tipo di variabili.
Il tipo bool
Le variabili di tipo bool occupano un solo byte e possono contenere solo i due valori: booleani true e
false. Per questo tipo sono definite solo le operazioni logiche ovvero && (AND), || (OR), ! (NOT).
!21
Corso sul Linguaggio C++ Edizione 2010
È importante notare che queste operazioni sono diverse dalle corrispondenti operazioni che operano
sui bit e che si applicano a tutte i tipi di variabili ovvero & (AND), | (OR), e ~(inversione dei bit).
Un esempio di dichiarazione di variabile bool è il seguente:
bool finito = false;
Nel linguaggio C il tipo bool non esiste, in sua vece si può utilizzare il tipo int infatti, come qualsiasi
altro dato, anche il risultato di un espressione logica è un numero binario e precisamente il numero 0
corrisponde al valore falso mentre il numero 1 o un numero diverso da zero corrisponde al valore
vero. Questo significa che, sia nel linguaggio C che nel linguaggio C++, si possono utilizzare come
variabili logiche anche le variabili intere.
L’operatore speciale sizeof
Per ottenere esattamente il numero di byte occupati da una variabile o da un tipo di dati si può ricorrere all’operatore speciale sizeof ovvero “misura di”. La sintassi è la seguente:
sizeof(<TipoDato>)
oppure
sizeof(<NomeVariabile>)
L’esempio che segue è un programma che mostra la quantità di memoria occupata da alcune variabili
elementari.:
#include <iostream.h>
#include <stdlib.h>
int main()
{
/* visualizza il numero di bytes assegnati in memoria ad alcune
variabili */
int i; short int si; long int li;
char c; wchar_t wc; float f; bool b;
double d; long double ld;
cout << "bytes occupati da char: " << sizeof(c)<< "\n";
cout << "bytes occupati da float: " << sizeof(f)<< "\n";
cout << "bytes occupati da double: " << sizeof(d)<< "\t long double: "
<< sizeof(ld) <<"\n";
cout << "bytes occupati da bool: " << sizeof(b)<< "\n";
cout << "bytes occupati da int: " << sizeof(i)<< "\t long int: " << sizeof(li) << "\t short int: " << sizeof(si)<<"\n";
cout << "bytes occupati da wchar_t: " << sizeof(wc) << "\n" ;
system("PAUSE");
return 0;
}
Mandandolo in esecuzione con il DEV-C++ si otterrà questo risultato:
!
2.5.Le espressioni
Un espressione è una sequenza di variabili, costanti e operatori, eventualmente racchiusi
a gruppi tra parentesi tonde () per modificare l’ordine dei calcoli.
Per esempio:
x = a * 3 / (somma - 5.3)
Nell’esempio x, a e somma sono variabili, 3 e 5.3 sono costanti, gli altri segni, escluse le parentesi che servono solo per modificare l’ordine dei calcoli, sono operatori. Un’espressione
può anche essere definita come una sequenza di operazioni elementari dove ogni operazione è
!22
Corso sul Linguaggio C++ Edizione 2010
definita da un segno detto operatore e da uno o più valori che possono essere variabili o costanti detti operandi.
Nel linguaggio C sono definiti molti più operatori rispetto agli altri linguaggi. Le espressioni
hanno molte più possibilità e questa è una delle caratteristiche che lo rende preferibile per alcune applicazioni. Per esempio sono stati introdotti operatori come quello dell’incremento o
decremento di una variabile che, in genere, sono presenti in tutti i linguaggi macchina ma non
nei linguaggi ad alto livello. In questi linguaggi operazioni come a++ o a-- del linguaggio C,
vengono sostituite con istruzioni del tipo a=a+1 o a = a-1, le quali però, tradotte in linguaggio
macchina, in genere, danno luogo a programmi meno efficienti.
Gli operatori del linguaggio C++ si possono raggruppare nelle seguenti categorie:
• Operatori di assegnamento
• Operatori aritmetici
• Operatori relazionali
• Operatori logici
• Operatori sui bit
• Operatori speciali
Gli operatori di assegnamento
L’operatore principale di assegnamento è il carattere =. Per esempio:
base = 3;
Con questa istruzione viene inserito 3 all’interno della variabile con nome ‘base’, questo significa che si inserisce il numero 3 nello spazio di memoria riservato alla variabile base.
x = y;
In questo caso il valore della variabile y vene copiato nella variabile x, le due variabili continueranno ad occupare spazi di memoria separati e indipendenti.
Nella maggior parte dei casi l’istruzione di assegnamento ha la seguente sintassi:
<identificatore> = <espressione>
e serve per inserire il risultato dell’espressione a destra del simbolo = nella variabile con
nome <identificatore>.
Per il linguaggio C++ questa è un’operazione che produce un valore come risultato. Il valore
risultante corrisponde al valore assegnato alla variabile.
Per questo motivo, in questo linguaggio, sono possibili le assegnazioni multiple del tipo:
prezzo = importo = q * pu;
in questo caso viene prima calcolato il prodotto delle variabili q e pu, il risultato viene assegnato alla variabile importo, lo stesso risultato viene assegnato anche alla variabile prezzo.
Esistono anche altri operatori di assegnazione, precisamente gli operatori +=, -=, *=, /=, %=,
<<=, >>=, &=, !=, ^=.
Si tratta della combinazione di operazioni aritmetiche o logiche con l’assegnazione. Sono state introdotte in C perché possono essere tradotte in modo efficiente in linguaggio macchina.
Per esempio le istruzioni:
km += 37;
k1 += k2;
a += (b/2);
equivalgono rispettivamente a:
km = km+37;
k1 = k1+k2;
a = a+(b/2);
Chi è pratico di programmazione avrà notato che questa è l’istruzione tipica degli accumulatori.
Ma l’operatore = si può anche utilizzare insieme ad altri operatori aritmetici, per esempio:
km -= 6;
// toglie 6 ai km percorsi ovvero km = km - 6
lato *= 2;
// moltiplica il lato per 2 ovvero lato = lato * 2
volume /= 3; // divide il volume per 3 ovvero volume = volume / 3
!23
Corso sul Linguaggio C++ Edizione 2010
quindi, più in generale vale la seguente sintassi:
<identificatore> <operatore>= <espressione>
corrisponde a
<identificatore> = <identificatore> <operatore> <espressione>
La sintassi completa per l’assegnamento è
<lvalue> <operatore di assegnamento> <rvalue>
dove <lvalue> sta per left value,ovvero valore di sinistra e può essere un identificatore ma anche un elemento di un vettore o un’espresssione che da come risultato un puntatore dereferenziato; <operatore di assegnamento> è uno degli operatori che abbiamo visto (=, +=, -=, *=, /=,
%=, <<=, >>=, &=, !=, ^=); <rvalue> (right value) è una qualsiasi espressione che restituisce un valore compatibile con il tipo di <lvalue>.
Operatori aritmetici
Naturalmente sono presenti nel linguaggio C++ gli operatori aritmetici disponibili negli altri
linguaggi per le operazioni fondamentali: addizione (+), sottrazione(-), moltiplicazione (*),
divisione (/), resto della divisione (%). Questi operatori vengono detti binari perché l’operazione viene compiuta su due operandi, per esempio:
b+c
a * 10
5/3
7-c
in generale per far eseguire l’operazione al computer si scrivono i due operandi con il segno
di operazione (l’operatore) in mezzo. Gli operatori binari non cambiano il valore dei due operandi ma memorizzano il risultato.
L’operazione % corrisponde al resto della divisione e si può eseguire solo con numeri interi,
per esempio: 10 % 3 da come risultato 1 e 20 % 5 da come risultato 0.
Oltre agli operatori visti sopra sono disponibili nel C++ anche l’operatore ++ e -- detti rispettivamente di incremento e decremento. Questi due operatori si applicano ad un solo operando
modificandone il valore per cui vengono detti unari. Il loro effetto è rispettivamente quello di
incrementare o decrementare di 1 il valore dell’operando.
Per esempio dopo l’esecuzione del seguente pezzo di programma:
int a=10, b=-20;
a++; b--;
nella variabile a ci sarà il valore 11 e nella variabile b il valore -21.
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. Le due notazioni vengono
dette rispettivamente prefissa e postfissa
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;
z = 4;
x = z++;
// due variabili intere
// z vale 4
// anche x vale 4 ma z vale 5
!24
Corso sul Linguaggio C++ Edizione 2010
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;
z = 4;
x = ++z;
// due variabili intere
// z vale 4
// 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.
Bisogna stare attenti e cercare di evitare che in una stessa espressione compaia più volte la
stessa variabile con applicate operazioni di incremento o decremento postfisse perché i risultati dipendono da quando il compilatore fa eseguire l’incremento o decremento, per esempio
dopo l’esecuzione delle seguenti istruzioni:
int b=5, a ; a=b++ + b++ ;
in b ci sarà il valore 7 e in a ci sarà il valore 10 perché i due incrementi di b verranno eseguiti
dopo l’addizione, mentre dopo l’esecuzione delle seguenti istruzioni:
int b=5; bool a; a= b++ < b;
in a ci sarà il valore vero perchè il compilatore Dev-C++ fa eseguire l’incremento di b prima
di eseguire il confronto <.
Operatori relazionali
Gli operatori relazionali sono operatori binari, servono per confrontare due valori e producono
un risultato booleano ovvero il valore true o false a seconda se il risultato del confronto è vero
o falso. Sono i seguenti:
>
maggiore
>=
maggiore o uguale
<
minore
<=
minore o uguale
==
uguale
!=
diverso
Per esempio: 5 >= 3 da risultato true; 2 == (10 / 5) da risultato true; 7 != 7 da risultato false;
Operatori logici
Gli operatori logici richiedono come operandi valori o espressioni booleane e il risultato è
ancora un valore logico di tipo vero o falso. Gli operatori logici sono:
||
OR
Risultato falso solo se entrambi gli operandi sono falsi
&&
AND Risultato vero solo se entrambi gli operandi sono veri
!
NOT
inverte il valore di verità dell’unico operando
Gli operatori || e && non valutano l’operando di destra se non è necessario, ovvero se il
primo operando è vero il risultato di || sarà vero indipendentemente dal valore del secondo
operando e quindi non serve valutarlo, nel caso del && se il primo operando è falso il risultato sarà falso senza bisogno di valutare il secondo operando.
Per esempio:
(5 > 1) || (3>6) è vero mentre (5>1) && (3 > 6) è falso
!25
Corso sul Linguaggio C++ Edizione 2010
Operatori sui bit
A tutte le variabili viene assegnato uno spazio di memoria dove viene memorizzato il valore
contenuto nella variabile. Il valore è sempre rappresentato tramite una serie di bit. Ogni bit è
una cifra binaria e quindi può assumere solo i due valori 0 e 1 che nell’algebra booleana rappresentano rispettivamente i valori falso e vero, per cui il valore di una qualsiasi variabile può
essere visto come una sequenza di valori vero e falso. Le operazioni sui bit sono operazioni
effettuate sui singoli bit che costituiscono il valore degli operandi considerati indipendentemente uno dall’altro.
Tutte queste operazioni, come pure quella di incremento e decremento, sono in genere disponibili in tutti i linguaggi macchina e quindi possono essere tradotte in modo molto efficiente
in questo linguaggio avvalorando la tesi che vuole il linguaggio C più vicina al linguaggio
macchina rispetto agli altri linguaggi di alto livello.
Gli operatori sui bit sono:
Operator
e
Descrizione
&
AND bit a bit, il risultato è 1 solo se entrambi i bit sono 1
|
OR bit a bit, il risultato è 1 solo se almeno uno dei due bit è 1
^
XOR (OR esclusivo) bit a bit, il risultato è 1 solo se uno solo dei due bit
è=1
~
Complemento a 1 ovvero inversione di tutti i bit
>>
Shift a destra. Spostamento a destra di tutti i bit con propagazione del
bit del segno (il primo bit più a sinistra), in pratica corrisponde a
dividere il numero binario per 2x dove x è il numero dei bit di
scorrimento. Se non si vuole la propagazione del segno bisogna
utilizzare le variabili unsigned.
<<
Shift a sinistra ovvero spostamento a sinistra di tutti i bit e riempimento
dei bit che si liberano a destra con zeri. In pratica corrisponde a
moltiplicare il numero per 2x dove x è il numero dei bit di scorrimento.
Per esempio supponiamo di aver definito due variabili con l’istruzione short int a=25,b=20,
considerato che il tipo short int ha una rappresentazione interna in binario a 16 bit con complemento a 2 per i numeri negativi, il contenuto delle due variabili corrisponderà ai due numeri 25 e 20 scritti in binario e sarà il seguente:
a = 0000000000011001
b = 0000000000010100
per cui si avrà che:
a & b ! 0000000000010000 = 16
a | b ! 0000000000011101 = 29
a ^ b ! 0000000000001101 = 13
~a ! 1111111111100110 = -26
~b ! 11111111111111101011 = -21
a >> 2 ! 0000 0000 0000 0110 = 6 (risultato dello spostamento a destra di due bit)
a << 2 ! 0000 0000 0110 0100 = 100 (risultato dello spostamento a sinistra di due bit)
!26
Corso sul Linguaggio C++ Edizione 2010
Per verificarlo basta scrivere il seguente programma:
#include <iostream.h>
#include <stdlib.h>
int main()
{
short int a=25, b=20 ;
cout << " a = " << a << "\t b = "<< b << endl;
cout << " a & b = " << (a & b) << "\t a | b = " << (a | b)
<< "\t a ^ b = " << (a ^ b) << endl;
cout << "~a = " << (~a) << "\t ~b = " << (~b) << endl;
cout << " a << 2 = "<<(a << 2)<<"\t a >> 2 = "<<( a >> 2)<< endl;
system("PAUSE");
return 0;
}
Si noti che invece della sequenza di escape \n si può utilizzare la costante predefinita endl per
inviare in output il carattere new line, mandandolo in esecuzione si otterrà il seguente output:
!
Regole di valutazione di un’espressione
Le espressioni possono essere combinazione di operatori e operandi anche complesse ma comunque portano sempre ad un risultato univoco. Per capire come il computer calcola una
espressione bisogna sapere che i calcoli vengono effettuati dall’unità aritmetico-logica (ALU)
che è una specie di calcolatrice contenuta nell’unità centrale di elaborazione (CPU) di ogni
computer. L’unità aritmetico-logica può eseguire una sola operazione alla volta e quindi per
calcolare un’espressione bisogna eseguire in sequenza le varie operazioni memorizzando i
risultati parziali così come faremmo noi con una calcolatrice normale.
Se per esempio consideriamo l’espressione 5 + 3 * 6, il risultato sarà diverso se eseguiamo
prima l’addizione e poi la moltiplicazione o viceversa prima la moltiplicazione e poi l’addizione. Nel primo caso esce 48 nel secondo esce 23. Il programmatore deve conoscere l’ordine
con cui il computer eseguirà i calcoli, per questo in ogni linguaggio di programmazione sono
state fissate delle regole che indicano come verrà calcolato il valore di una qualsiasi espressione, stabilendo esattamente l’ordine con cui devono essere applicati gli operatori agli operandi. Le regole per il linguaggio C++ sono le seguenti:
1. L’impiego di parentesi. Se si utilizzano le parentesi tonde, le espressioni racchiuse
all’interno delle parentesi vengono calcolate prima di eseguire i calcoli posti fuori dalle parentesi. Il compilatore traduce l’espressione in modo da far calcolare prima le
espressioni racchiuse nelle coppie di parentesi più interne, poi sostituisce tutto il blocco che inizia con “(“ fino a “)” con il risultato dell’espressione, e procede man mano
fino a quelle più esterne;
2. Livello di precedenza degli operatori. Gli operatori sono divisi in gruppi con livelli
di precedenza diverso, in mancanza di parentesi vengono prima eseguite prima le operazioni con livello più alto, poi le altre in ordine fino a quelle di livello più basso. Per
conoscere il livello di precedenza delle operazioni si veda la Tabella 2 che segue, dove
sono riportati tutti gli operatori divisi in gruppi in base al livello di priorità. Per esem!27
Corso sul Linguaggio C++ Edizione 2010
pio le moltiplicazioni e le divisioni vengono eseguite prima delle addizioni e sottrazioni, quindi l’espressione precedente 5 + 3 * 6 produce il risultato 23;
3. Le regole di associatività. Quando c’è una serie di operandi e operatori con lo stesso
livello di precedenza, si seguono le regole di associatività. Per la maggior parte degli
operatori vale l’associatività a destra, cioè le operazioni vengono eseguite partendo da
quella più a sinistra fino a quella più a destra, fanno eccezione gli operatori di assegnamento per i quali vale l’associatività a sinistra.
Quindi, quando viene calcolata un espressione scritta in C++ vengono prima calcolate le
espressioni racchiuse tra parentesi, poi vengono eseguiti in calcoli in ordine di precedenza degli operatori, se ci si trova con una sequenza di operandi e operatori con lo stesso livello di
precedenza si segue la regola dell’associatività, questo significa che se si trova un espressione
del tipo:
operando1 op1 operando2 op2 operando3
dove <op1> e <op2> sono operatori con lo stesso livello di priorità allora il computer segue la
regola dell’associatività, se l’associatività è a destra, come avviene normalmente per la maggior parte delle operazioni, si procede da sinistra verso destra e precisamente si calcolerà:
(operando1 op1 operando2) op2 operando3
se invece l’associatività è a sinistra (come avviene per l’operatore =) si procederà da destra
verso sinistra e quindi si calcolerà:
operando1 op1 (operando2 op2 operando3)
Operatori speciali
Vedremo solo due operatori speciali:
?
utilizzato con tre operandi (ternario), una espressione logica e due
espressioni qualsiasi dello stesso tipo, produce il risultato di una delle due
espressioni scegliendolo in base al valore dell’espressione logica;
,
utilizzato con due operandi (binario), ha il più basso livello di priorità,
inferiore anche agli operatori di assegnamento, è associativo a destra, fa calcolare dal computer in sequenza le due espressioni, rendendo possibile l’utilizzo del risultato della prima nella seconda;
La sintassi dell’operazione ? è la seguente:
<espressione logica>?<espressione1>:<espressione2>
si utilizza quando vogliamo sceglier tra due risultati diversi in base ad una condizione. Per
esempio se lo sconto è del 10% quando si acquista una quantità di prodotto che va da 1 a 5
mentre è del 20% se si acquistano più di 5 unità del prodotto, per assegnare il valore alla variabile sconto possiamo utilizzare la seguente espressione:
sconto = quant > 5 ? 20 : 10;
Si noti che nell’espressione precedente non servono le parentesi perché in base alla precedenza degli operatori (vedi Tabella 2 sotto) viene eseguita prima l’operazione >, poi
l’operazione ? ed infine l’operazione =.
Se i possibili sconti fossero stati tre, per esempio 5% fino a due pezzi, 10% da tre pezzi a cinque e 20% oltre i 5 pezzi, avremmo potuto calcolare lo sconto sempre con una sola istruzione
nel modo seguente:
sconto = quant > 5 ? 20 : (quant >2 ? 10 :5);
La sintassi dell’operazione , (virgola) è la seguente:
<espressione1>,<espressione2>
potendosi ripetere l’operazione quante volte si vuole si possono scrivere anche espressioni del
tipo:
<espressione1>,<espressione2>,<espressione3>, …….,<espressioneN>
!28
Corso sul Linguaggio C++ Edizione 2010
L’effetto di queste operazioni è semplicemente quello di far calcolare al computer le espressioni nell’ordine partendo dalla prima più a sinistra fino all’ultima a destra. Se qualcuna di
queste espressioni contiene operazioni di assegnamento, nelle seguenti verranno eventualmente utilizzati i valori delle variabili così come modificate delle espressioni precedenti. Per
esempio, con l’istruzione:
k = (i=10, j=20, i+j);
alla variabile k verrà assegnato il valore 30.
Si noti che in questo caso l’utilizzo delle parentesi è indispensabile per far eseguire l’operazione , (virgola) prima dell’assegnamento (operazione =), senza parentesi a k sarebbe stato
assegnato il valore 10.
!29
Corso sul Linguaggio C++ Edizione 2010
Riassunto degli operatori del linguaggio C++
Tabella 2. Gli operatori disponibili nel linguaggio C++ raggruppati in ordine di precedenza da
quelli con precedenza maggiore fino a quelli con precedenza minore (le linee più marcate segnano
la divisione tra un gruppo e l’altro).
!30
Corso sul Linguaggio C++ Edizione 2010
Simbol
o
Rappresenta l’operazione ….
Sintassi
::
visibilità
.
Selezione elemento
<oggetto>.<elemento>
->
Selezione elemento
<puntatore>-><elemento>
[]
Indicizzazione
<identificatore>[<espressione>]
()
Chiamata di funzione
<nome_funz.>(<lista parametri>)
()
Conversione di tipo
sizeof
Dimensione di un oggetto
sizeof
Dimensione di un tipo di dati
<nome_calsse>::<elemento>
<tipo dati>(<espressione>)
sizeof(<espressione>)
sizeof(<tipo dati>)
++
Incremento prefisso
++<variabile>
++
Incremento postfisso
<variabile>++
--
Decremento prefisso
--<variabile>
--
Decremento postfisso
<variabile>--
~
Inversione dei bit
~<espressione>
!
NOT
-
Cambiamento di segno
-<espressione numerica>
+
Più unario
+<espressione numerica>
&
Indirizzo di
&<identificatore>
*
Dereferenziazione
*<espressione>
Allocazione dinamica
new <tipo dato>
new
delete
!<espressione logica>
Deallocazione dinamica
delete <puntatore>
delete[] Deallocazione di un array
delete[] <puntatore>
()
Conversione di tipo nella notazione
cast
(<tipo dato>)<espressione>
.*
Selezione indirizzo elemento
<oggetto>.*<puntatore_elemento>
->*
Selezione indirizzo elemento
<puntatore>->*<puntatore_elemen.>
*
Moltiplicazione
<espressione>*<espressione>
/
Divisione
<espressione>/<espressione>
%
Resto della divisione
<espressione>%<espressione>
+
Addizione
<espressione>+<espressione>
-
Sottrazione
<espressione>-<espressione>
!31
Corso sul Linguaggio C++ Edizione 2010
Simbol
o
Rappresenta l’operazione ….
Sintassi
<<
Shift a sinistra
<espressione> << <numero bit>
>>
Shift a destra
<espressione> >> <numero bit>
<
Minore di
<espressione> < <espressione>
<=
Minore o uguale a
<espressione> <= <espressione>
>
Maggiore di
>=
Maggiore o uguale a
<espressione> >= <espressione>
==
Uguale a
<espressione> == <espressione>
!=
Diverso da
<espressione> != <espressione>
&
And bit a bit
<espressione> & <espressione>
^
XOR (OR esclusivo) bit a bit
<espressione> ^ <espressione>
|
OR bit a bit
<espressione> | <espressione>
&&
AND logico
<espr.logica> && <espr.logica>
<espressione> > <espressione>
||
OR logico
?
Espressione condizionale
<espr.logica>?<espr1>:<espr2>
=
Assegnazione
<identificatore>=<espressione>
*= /= Assegnazione composta
%= +=
-= <<=
>>=
&= |=
^=
<identificatore><operatore>=<espressione
>
,
<espr.logica> || <espr.logica>
Virgola (esegue le due espressioni in
sequenza)
<espressione1>,<espressione2>
2.6.La conversione di tipo
Abbiamo visto che una espressione può consistere in più calcoli e che il computer esegue
questi calcoli uno alla volta memorizzando i risultati intermedi in variabili temporanee che
poi utilizza nei calcoli successivi. Il tipo di queste variabili temporanee dipende dall’operazione e in genere è sempre dello stesso tipo degli operandi utilizzati.
Per esempio consideriamo il seguente programma:
int main()
{
int uno=1, due=2;
float tre;
tre = uno/due;
cout << tre <<endl;
!32
Corso sul Linguaggio C++ Edizione 2010
}
system("PAUSE");
return 0;
Ci aspetteremmo di vedere in output il risultato 0.5, visto che la variabile tre è di tipo float,
invece verrà visualizzato 0. Questo dipende dal fatto che con il linguaggio C++, il calcolo
uno/due, produce un risultato di tipo int essendo i due operandi uno e due entrambi di tipo int.
Il risultato sarà quindi 0 e non 0.5.
Il problema si verifica quando in un’espressione gli operandi sono di tipo diverso, infatti ci
sono operazioni che permettono, entro certi limiti, l’utilizzo di operandi di tipo diverso, per
esempio possiamo eseguire operazioni aritmetiche con un operando di tipo double e un altro
di tipo int oppure, come nel programma precedente, possiamo assegnare ad un variabile di
tipo float un valore intero.
Quando gli operandi di un’operazione sono di tipo diverso, il linguaggio C++ sceglie per il
risultato temporaneo dell’operazione, il tipo più capiente tra quello degli operandi in modo da
evitare perdita di informazioni, e, prima di fare il calcolo, converte l’altro operando nel tipo
scelto. Si dice in questo caso che viene effettuata una conversione implicita di tipo detta cast
implicito.
Il tipo double è più capiente del tipo float ed entrambi sono più capienti del tipo int perché
qualsiasi numero intero può essere memorizzato in una variabile di tipo float o double (che
accettano rispettivamente numeri fino a 1038 e 10308) mentre se spostiamo una variabile di tipo
float in una intera perderemo la parte dopo la virgola. Ogni volta che si assegna un valore di
un tipo più capiente ad una variabile meno capiente si può avere una perdita di informazioni,
per esempio se assegniamo un valore double ad una variabile float è molto probabile che ci
sarà una diminuzione del numero di cifre significative corrette.
Se mettiamo in ordine i tipi numerici dal meno capiente al più capiente abbiamo la seguente
sequenza:
char!short int!int!long int!float!double!long double
per esempio dopo l’esecuzione delle seguenti istruzioni:
int uno=1, float due=2.0, tre;
tre = uno/due;
alla variabile tre verrà assegnato correttamente il valore 0.5 perché il computer quando esegue
l’operazione uno/due convertirà automaticamente il valore di uno in float, eseguirà una divisione tra numeri con la virgola e memorizzerà il risultato temporaneo in una variabile di tipo
float.
È anche possibile indicare al computer il tipo di dati in base al quale deve essere svolta l’operazione usando il cosiddetto cast esplicito la cui sintassi è:
(<tipo dati>)<espressione>
Per esempio per far funzionare correttamente il programma precedente, senza modificare il
tipo delle variabili, si può modificare l’istruzione per la divisione nel seguente modo:
int main()
{
int uno=1, due=2;
float tre;
tre = (float) uno/due;
cout << tre <<endl;
system("PAUSE");
return 0;
}
!33
Corso sul Linguaggio C++ Edizione 2010
premettendo la parola (float) tra parentesi all’espressione, si forza il computer ad eseguire i
calcoli con il tipo float.
È possibile convertire i dati da un formato ad un altro anche utilizzando le funzioni di conversione la cui sintassi è:
<tipo dati>(<espressione>)
per esempio: int(10.5*3) → 31 invece di 31.5, char(6*10+5) produce il numero 65 in uno
spazio di un solo byte.
Ma in questo caso l’espressione viene calcolata normalmente e, solo dopo, il risultato viene
convertito nel formato specificato. Quindi se nel programma precedente avessimo scritto
float(uno/due) invece di (float)uno/due avremmo ottenuto come risultato 0 invece di 0.5, perché l’espressione uno/due tra due numeri interi da 0 e questo risultato, trasformato in float, è
sempre 0.
2.7.Le enumerazioni
Fra i tipi elementari introdotti nel paragrafo 2.4 c’è anche il tipo enum. In realtà non si tratta
di un vero tipo di dati ma di un insieme di possibili tipi che il programmatore può definire. In
pratica il programmatore può definire un nuovo tipo attraverso un elenco di identificatori che
rappresentano i possibili valori che questo tipo può assumere. Per esempio:
enum colori {giallo, arancione, rosso, verde, blu};
// (1)
In questo modo viene creato un nuovo tipo di dati che si chiama colori e che può assumere
solo cinque valori diversi a cui vengono assegnati i nomi giallo, arancione, rosso, verde, blu.
Dopo aver definito il tipo colori, come per qualsiasi altro tipo, per utilizzarlo dobbiamo definire le variabili, per esempio:
colori a,b;
a e b diventano variabili di tipo colori. A queste variabili, nel programma, si potrà assegnare
solo valori di tipo colori.
a = rosso; b = verde;
// (2)
In realtà il compilatore associa ogni identificatore dell’elenco fornito dal programmatore con
un numero intero e nel programma considera questi identificatori come costanti dichiarate dal
programmatore.
Nell’esempio dell’istruzione (1), le parole giallo, arancione, rosso, verde, blu, diventano costanti esattamente come se fossero state definite con l’istruzione:
const int giallo=0, arancione=1, rosso=2, verde=3, blu=4;
Quindi le variabili di tipo colori sono in realtà delle variabili di tipo intero a cui, però, si possono assegnare solo i numeri da 0 a 4. Con l’istruzione (2) viene assegnato il numero 2 alla
variabile a e il numero 3 alla variabile b. Se si visualizza in output un variabile di tipo colori
verrà visualizzato il numero contenuto al suo interno e non il nome del colore associato a quel
numero!
Le operazioni ammesse con le variabili di tipo dichiarato attraverso l’istruzione enum sono le
stesse ammesse con il tipo intero, quindi ++, --, +, -, *, /, %. Inoltre queste variabili sono
compatibili con il tipo intero.
!34
Corso sul Linguaggio C++ Edizione 2010
Abbiamo visto che il computer assegna automaticamente i numeri da zero in poi agli identificatori definiti nelle enumerazioni ma il programmatore può anche decidere lui quali numeri
assegnare, per esempio:
enum mesi {gennaio=1, febbraio, luglio=7, agosto};
mesi mese1, mese2;
si avrà gennaio = 1, febbraio =2, luglio = 7, agosto =8
inoltre, si possono anche dichiarare le variabili con la stessa istruzione enum:
enum mesi {gennaio=1, febbraio, luglio=7, agosto} mese1,mese2;
2.8.Esercizi
1) Calcolare le seguenti espressioni scritte nel linguaggio C++
a) 3*(15-2*5)/(4*10/8)
b) 2+5*(40 / (2*4) /2)+(10/3)
[Risultato:3; 15;]
2) Scrivere le espressioni logiche per:
• Vedere se un numero x è positivo
• Vedere se un numero x è pari;
• Vedere se un numero x è compreso nell'intervallo [A, B] chiuso;
• Vedere se un numero x è esterno all'intervallo [A, B] chiuso;
• Vedere se un numero intero x è multiplo di 5 e, contemporaneamente, è dispari;
3) Calcolare ili risultato delle seguenti espressioni logiche (1 per "vero", 0 per "falso")
5>2;
10<3;
5>7 || 3>4;
10<2 || 5>4;
7<1 || 4<5;
3>0 && 5>2;
8>10 && 5>2; 7>8 != 7>10;
3>2 != 2<3;
5<5 == 4>3;
4) Sia dato il seguente pezzo di programma:
long int d = 1267894; float media;
int k = 10;
media = d/k;
cout << (float) media;
qual è il valore che viene stampato?
5) Indicare il valore assunto dalla variabile f nelle seguenti espressioni:
int a=1, b=2, c=3, d=4, e=5, f;
a) f = 5 + --a - e / b++;
b) f = ++a - c-- + e/--b;
c) f = d + c * b-- + e / a++;
6) Indicare il valore assunto dalla variabile c nelle seguenti espressioni:
int a=5, b=6, c;
a) c = (a == b) ? ++a : ++b;
b) c = (a++ == b) ? b++ : b--;
c) c = (++a == b) ? ++b : --b;
7) Determinare quale è la relazione che assume valore vero quando x è esterno all'intervallo
[A,B] e y è interno allo stesso intervallo?
a) (x<A) && (x>B) && (y>=A) && (y<B);
b) ((x<A)||(x>B)) && ((y>=A)&&(y<=B));
c) ((x<A)||(x>B)) && ((y>=A)||(y<=B));
!35
Corso sul Linguaggio C++ Edizione 2010
d)
e)
f)
((x<A)||(x>B)) || ((y>=A)||(y<=B));
((x<A)&&(x>B)) && ((y>=A)||(y<=B));
((x<A)||(x>B)) || ((y>=A)&&(y<B));
8) Sia data una variabile dichiarata come char c;. Ipotizzando che essa contenga un carattere
compreso tra '0' e '9', come si trasferisce in una variabile intera v il valore decimale della
cifra rappresentata da c?
a) v = atoi(c); (atoi- ascii to int- trasforma una stringa contenente cifre in un numero int
- come val() del Basic- ma il parametro deve essere un puntatore)
b) v = (int) c ;
c) v = c - '0';
d) v = c ;
e) nessuna delle precedenti
9) Quale dei seguenti valori di a e b produce il valore vero per la condizione: (a > 0) && ((b < 0) || (b > 1))
Risposte: a)a = 5; b = 0
b)a = 5; b = 2
c)a = -1; b = 5
d)a = 1; b = 1
10) Data una misura di tempo espressa in ore minuti e secondi descrivere un algoritmo che la
trasformi in secondi.
11) Descrivere un algoritmo per trasformare una misura espressa in secondi in un'altra espressa in ore minuti e secondi.
12) Dato un numero n compreso tra 1 e 365, considerandolo come giorno n-esimo dell'anno,
descrivere un algoritmo per determinare a quale giorno della settimana corrisponde sapendo che il primo giorno dell'anno era domenica. (output un numero da 1 a 7, 1=lunedì
7 = domenica.)
13) Assegnata la paga oraria di un operaio calcolare la paga settimanale sapendo che si lavora
7 ore al giorno, il sabato si lavora solo 4 ore pagate però il doppio e la domenica non si
lavora.
14) Trovare l’algoritmo per calcolare il numero medio di medici per paziente in un giorno
qualsiasi dell’anno in un ospedale di cui si conosce il numero dei medici, il numero totale
dei pazienti che circolano in un anno e il numero medio di giorni di degenza di ogni paziente.
15)
Convertire lire in Euro (1 euro = 1936,27 lire)
16) Data una misura espressa in metri trovare l’equivalente in piedi e yarde sapendo che:
3 piedi = 1 yarda = 0,91439 metri
17) Sapendo che si può passare dai gradi Celsius ai gradi Fahrenheit con la seguente formula:
gradi Fahrenheit = gradi Celsius * 9/5 + 32
Scrivere un programma per trasformare una misura della temperatura da gradi Celsius a Fahrenheit e uno per fare il contrario.
Risposte esercizi
Esercizio 4) = 126789
Esercizio 5) a) = 3; b) = 4; c) = 15
!36
Corso sul Linguaggio C++ Edizione 2010
Esercizio 6): a) = 7; b) = 6; c) = 7
Esercizio 7) = b)
Esercizio 8) = c) c-‘0’
Esercizio 9) = b)
!37
Corso sul Linguaggio C++ Edizione 2010
3
Capitolo
3.Le istruzioni e le strutture di controllo
Un programma C++ è un insieme di istruzioni. Le istruzioni possono essere di due tipi:
• Istruzioni eseguibili, corrispondono ad un azione eseguita dal computer;
• Istruzioni di dichiarazione, non corrispondono a nessuna operazione ma servono per definire il modello dei dati o gli oggetti utilizzati dal programma oppure danno indicazioni al compilatore sulle funzioni utilizzate nel programma.
Nel programma sorgente è possibile alternare a piacere istruzioni dichiarative ed eseguibili purché
quando si utilizza un oggetto quest’ultimo sia stato già definito in precedenza.
Le istruzioni possono essere anche classificate nel seguente modo:
Di assegnazione
Espressioni
semplici
chiamata di
Di dichiarazione e
definizione
Istruzioni del
C++
return
break
Di salto
continue
goto
blocco
strutturate
selezione
if ... else
switch
while
cicli
do…whilee
for ….
!
3.1.La programmazione strutturata
Abbiamo visto che il linguaggio C++ permette di implementare sia i programmi realizzati con
il modello procedurale che quelli realizzati secondo il modello della programmazione object
oriented, entrambi, però, prevedono la traduzione di algoritmi nel linguaggio di programma!38
Corso sul Linguaggio C++ Edizione 2010
zione, anche se nella programmazione procedurale, questa è l’operazione base che realizza
l’attività del “programmare”.
Sappiamo che un algoritmo è la descrizione di un procedimento ovvero di una serie finita di
azioni che opera su un’insieme di dati in ingresso per produrre un insieme di risultati. Questa
descrizione deve essere non ambigua ovvero un qualsiasi esecutore che esegue l’algoritmo, se
parte dagli stessi dati, deve eseguire esattamente le stesse azioni e deve arrivare esattamente
agli stessi risultati. Un algoritmo, inoltre, rappresenta sempre un procedimento generale che si
può eseguire più volte cambiando i dati in input. Le azioni che verranno svolte, possono essere diverse a seconda dei dati iniziali. Quindi, nell’algoritmo, oltre alla descrizione chiara e
univocamente interpretabile delle azioni da eseguire, viene anche indicato l’ordine con cui
queste azioni devono essere eseguite, inoltre ci può essere l’indicazione che una o più azioni
devono essere ripetute e/o eseguite solo in alcuni casi. Queste indicazioni non sono descrizioni di azioni che l’esecutore deve compiere ma piuttosto servono a indicare esattamente la sequenza con cui le azioni devono essere eseguite e quando devono essere eseguite. Se l’algoritmo viene descritto con un diagramma di flusso (detto anche diagramma a blocchi) le azioni
sono descritte in rettangoli mentre la sequenza di esecuzione (flusso) e le condizioni che determinano l’esecuzione o meno delle azioni sono rappresentate dalle frecce e dai rombi, dando
luogo a schemi grafici diversi quando si cambiano le indicazioni relative a come si susseguono le azioni. I vari modi con cui mettere insieme le azioni per formare un algoritmo vengono
definiti da alcuni autori1 modelli di composizione o schemi di composizione ma sono noti in
generale come strutture di controllo della programmazione. I principali modelli di composizione sono: La sequenza, la selezione e la ripetizione:
La sequenza consiste nella descrizione di una serie di azioni che devono essere eseguite una
dopo l’altra nell’ordine indicato, per esempio:
Inizio
!
Azione 1
…
Azione 2
Azione N
Fine
La selezione consiste nella descrizione di una o più azioni che devono essere eseguite solo se
si verifica una determinata condizione, per esempio:
La ripetizione o ciclo consiste nella descrizione di una o più azioni che devono essere rip e t u t e u n n umero di
v o l t e variabile in base ad
zione fissata.
no
si una condiPer esempio:
condizione
condizione
Se cons i d eriamo tutti i
si d i agrammi
condi flusso
A )
B )
che si
no
condizione
possono
realizzare
u t i l i zzando solo
g l i
schemi
A) Ripetizione precondizionale
B) Ripetizione postcondizionale
di composizione di sequenza, selezione e ripetizione sopra indicati e supponiamo che un azione rappresentata nello schema possa essere o un’azione elementare che l’esecutore capisce o un
azione complessa corrispondente ad una serie di azioni elementari rappresentabile sempre con
uno dei tre schemi base su indicati, otteniamo un sottoinsieme di tutte le descrizioni di algoritmi possibili. Questo sottoinsieme è quello degli schemi di flusso strutturati.
1 A. Andronico
e altri, Manuale di Informatica, Zanichelli 1979
!39
Corso sul Linguaggio C++ Edizione 2010
In base al famoso teorema enunciato dai due matematici italiani Böhm e Jacopini2, un qualsiasi algoritmo può sempre essere descritto utilizzando uno schema di flusso strutturato e
quindi usando solo le strutture di controllo della sequenza, selezione e ripetizione. Anzi il teorema afferma che basta anche solo la struttura della sequenza, quella della selezione ad una
via e un solo tipo di ciclo (per esempio quello postcondizionale).
Per far eseguire un algoritmo da un computer bisogna descriverlo utilizzando un linguaggio
che possa essere, in qualche modo, compreso dal computer. Hanno tale caratteristica i linguaggi di programmazione.
Ogni azione elementare dell’algoritmo deve corrispondere ad un’istruzione elementare del
linguaggio di programmazione utilizzato. Per comunicare al computer gli schemi di composizione delle azioni si utilizzano le istruzioni di controllo. Il teorema di Böhm-Jacopini ci assicura che in un linguaggio, per poter tradurre un qualsiasi algoritmo, bastano le istruzioni di
controllo per la sequenza, selezione e ripetizione purché all’interno di queste istruzioni si
possa inserire una qualsiasi altra istruzione (elementare o di controllo). I linguaggi di programmazione che possiedono le istruzioni di controllo con le caratteristiche su menzionate
sono detti linguaggi strutturati.
Si è visto che l’utilizzo di un linguaggio strutturato rende più semplice individuare gli errori
nei programmi perché permette di evitare l’utilizzo dell’istruzione di salto (l’istruzione goto).
Quest’ultima istruzione era molto utilizzata nei primi linguaggi di programmazione e permette la traduzione di un qualsiasi schema, ma rende molto più complesso, per il programmatore,
tenere sotto controllo il flusso del programma ovvero la sequenza delle azioni che verranno
eseguite in tutti i casi possibili.
Il primo linguaggio strutturato fu il Pascal, oggi tutti i linguaggi moderni di programmazione
sono linguaggi strutturati.
I programmi che utilizzano solo le istruzioni di controllo per i tre schemi base visti sopra sono
detti programmi strutturati3.
Il linguaggio C (e di conseguenza anche il linguaggio C++) è un linguaggio strutturato. Nei
prossimi paragrafi vedremo le istruzioni utilizzate per tradurre le tre strutture di controllo fondamentali della programmazione in questo linguaggio.
3.2.Le istruzioni semplici
La principale istruzione semplice è quella di assegnazione che abbiamo già visto. Abbiamo
già visto anche le istruzioni per la dichiarazione di variabili, le istruzioni per dichiarare e definire oggetti di altro tipo le vedremo man mano che studieremo gli oggetti in questione.
Ogni istruzione semplice finisce sempre con il carattere ; (punto e virgola), esiste anche l’istruzione nulla costituita dal solo carattere ;
;
Se viene inserita in un programma serve a dire al computer che il quel punto non deve fare
niente.
In questo paragrafo vedremo le istruzioni di salto:
break
continue return
goto
Normalmente le istruzioni di un programma vengono eseguite una di seguito all’altra, nell’ordine in cui sono scritte, inoltre è possibile utilizzare le istruzioni di controllo come quelle di
selezione per far eseguire alcune istruzioni si e altre no, oppure quelle di ripetizione per far
ripetere più volte una serie di istruzioni.
2
vedi http://it.wikipedia.org/wiki/Teorema_di_Jacopini-Bohm.
3
Vedi http://it.wikipedia.org/wiki/Programmazione_strutturata.
!40
Corso sul Linguaggio C++ Edizione 2010
In ogni istante è in esecuzione una sola istruzione del programma ed esiste nella CPU un puntatore che indica la posizione della prossima istruzione che sarà eseguita, questo puntatore si
chiama program counter. Con le istruzioni di salto è possibile modificare la sequenza con cui
dovrebbero essere svolte le istruzioni del programma e, quindi, tutte le istruzioni di salto producono la modifica del program counter.
Le istruzioni break e continue servono per modificare la normale sequenza con cui vengono
eseguite le istruzioni in un blocco interno ad una selezione o ad un ciclo e le vedremo nei
prossimo paragrafi. L’istruzione return determina la fine dell’esecuzione di un sottoprogramma e fa tornare il punto di esecuzione al programma chiamante. Come abbiamo già visto
return serve anche per terminare il programma principale main.
L’istruzione goto (go to = vai a) è detta istruzione di salto incondizionato e produce come
effetto il trasferimento del punto di esecuzione ad una posizione definita dal programmatore.
La sintassi è:
goto <etichetta>
Questo comando ordina al computer di portare il punto di esecuzione nella posizione in cui il
programmatore ha posizionato l’etichetta. Una etichetta è un qualsiasi identificatore valido
seguito dal carattere : (duepunti). Per esempio:
inizio:
contatore++;
……….
goto inizio;
L’uso di questa istruzione, come detto nel paragrafo precedente, può e dovrebbe essere evitato
perché rende difficile il controllo del programma durante l’esecuzione. Al suo posto si possono utilizzare le istruzioni strutturate elencate nei prossimi paragrafi.
3.3.La sequenza
Per dire al computer di eseguire una serie di istruzioni in un determinato ordine nel linguaggio
C si utilizza il blocco:
{ <istruzione1>;<istruzione2>; ………[<istruzioneN]; }
In pratica si scrivono le istruzioni nell’ordine in cui devono essere eseguite (se si trattta di
istruzioni semplici devono finire con il carattere ; -punto e virgola-) e si racchiude l’elenco tra
parentesi graffe, un tale insieme di istruzioni si dice blocco.
Le istruzioni interne ad un blocco possono essere istruzioni elementari o istruzioni di controllo. Se si utilizza il linguaggio C++ si possono inserire in un blocco anche istruzioni di dichiarazione.
Per esempio tutte le istruzioni della funzione main nei programmi che abbiamo visto sono un
blocco. Un blocco può contenere al suo interno una qualsiasi istruzione di controllo e quindi
anche altri blocchi. Per esempio:
int main() {
int i=1;
{ int j=20; k=30;
……
}
i++;
……..
return 0; }
}
blocco interno
il blocco contenente tutte le istruzioni della funzione main contiene al suo interno un altro
blocco che inizia con le dichiarazioni int j=20; k=30.
Il raggruppamento delle istruzioni in blocchi è importante per l’area di validità delle variabili, infatti ogni variabile dichiarata in un blocco può essere utilizzata solo nelle istruzioni del
!41
Corso sul Linguaggio C++ Edizione 2010
blocco stesso e in quelle di tutti i blocchi contenuti in esso che seguono la dichiarazione, ma
non può essere utilizzata al di fuori del blocco.
Quindi nell’esempio precedente la variabile i può essere utilizzata sia nel blocco che inizia
dopo di int main() che in quello interno, mentre le variabili j e k possono essere utilizzate solo
nelle istruzioni racchiuse tra le due parentesi graffe del blocco interno.
Area di validità delle variabili
Le variabili dichiarate in un blocco si dicono variabili locali appunto perché possono essere
utilizzate solo all’interno del blocco. È possibile però definire anche variabili globali che
valgono in tutti i blocchi, per farlo bisogna dichiarare le variabili fuori da qualsiasi blocco,
subito dopo le direttive al preprocessore, per esempio:
#include <iostream.h>
// variabili globali
int totale=0;
int main() {
float prezzo; int q;
}
la variabile totale è una variabile globale mentre le variabili prezzo e q sono variabili locali
della funzione main.
Ciclo di vita delle variabili
Tutte le variabili vengono create quando viene eseguita la dichiarazione ma le variabili globali
vengono cancellate solo alla fine del programma mentre, normalmente, le variabili locali
vengono cancellate quando termina il blocco in cui sono state dichiarate. È possibile evitare la
cancellazione delle variabili locali alla fine del blocco utilizzando il modificatore della modalità di memorizzazione static che abbiamo visto nel paragrafo 2.2. Per esempio consideriamo
il seguente programma:
int main()
{ int i;
for (i=1; i<10; i++) /*ripete 9 volte il blocco sottostante */
{ static int contatore=1;
cout << contatore << ";" ;
contatore++;
}
cout << endl;
system("PAUSE");
return 0;
}
Sapendo che l’istruzione for è una delle istruzioni di controllo per i cicli che vedremo fra
poco e che in questo caso ha semplicemente l’effetto di far ripetere 9 volte le istruzioni del
blocco interno, il risultato in output sarà:
1;2;3;4;5;6;7;8;9;
Premere un tasto per continuare ...
Mentre se si toglie la parola static nella dichiarazione della variabile contatore il risultato
sarà:
1;1;1;1;1;1;1;1;1;
Premere un tasto per continuare ...
perché alla fine del blocco la variabile verrà cancellata e quindi, quando il blocco viene ripetuto, la variabile contatore viene ricreata con il valore 1.
Anche le variabili globali possono essere definite static, in questo caso non viene modificato
il ciclo di vita, perché tutte le variabili globali vengono cancellate alla fine del programma,
ma viene modificata l’area di validità ed ha senso quando il programma è costituito da più
moduli ovvero più file sorgenti, in quanto la variabile sarà visibile solo nel modulo dove è
!42
Corso sul Linguaggio C++ Edizione 2010
stata definita mentre normalmente le variabili globali sono visibili in tutti i moduli dal momento in cui sono state definite in poi.
3.4.La Selezione
Il linguaggio C++ prevede due istruzioni per la selezione: l’istruzione if per la selezione
semplice a una o due vie e l’’istruzione switch per la selezione a più vie.
La sintassi dell’istruzione if è la seguente:
if
(
espressione logica
)
Istruzione1
else
!
Istruzione2
durante l’esecuzione il computer valuta l’espressione logica, se il risultato è vero (diverso da
zero) verrà eseguita l’istruzione1 altrimenti, se è presente la clausola else, verrà eseguita l’istruzione2. Se non c’è la clausola else la selezione è ad una sola via, altrimenti è a due vie. L’istruzione o le istruzioni presenti dentro l’if possono essere sia istruzioni semplici che strutturate, quindi possono essere anche un blocco ({ ……}) oppure un’altra istruzione if, in questo
caso si dice che la seconda istruzione if è annidata nella prima. Il blocco deve obbligatoriamente essere utilizzato se le istruzioni da eseguire nel caso vero o nel caso falso sono più di
una.
Per esempio:
If (a > b) max = a ;
oppure
if (a > b) {tmp=a ; a=b ; b=tmp ;}
sono entrambe selezioni ad un via, l’istruzione max=a nel primo caso e il blocco costituito da
tre istruzioni nel secondo caso, verranno eseguiti solo se a>b.
Le seguenti istruzioni if sono esempi di selezione a due vie.
If (b == 0) cout << "Indetermintata !"; else
cout << "Impossibile!";
If (a >10)
{e++ ; a =\ 10;}
else
{e-- ; a=*10 ;}
Problema: equazione di primo grado
Scrivere un programma per far risolvere al computer una qualsiasi equazione di primo grado
in una variabile.
Analisi del problema
Si definisce equazione di primo grado in una variabile una qualsiasi equazione matematica
riconducibile alla forma:
ax+b=0
dove a e b sono due numeri qualsiasi. Risolvere un'equazione significa trovare tutti i numeri
che sostituiti alla x verificano l'uguaglianza. Si può dimostrare che
Se a<> 0 allora esiste una sola soluzione : x = -b/a
Se a= 0 e b<>0 allora l'equazione non ammette soluzioni
Se a=0 e b=0 allora le soluzioni sono infinite
Noi ci limiteremo alle equazioni nel campo dei numeri reali. Per risolvere un equazione di
primo grado è necessario conoscere il valore di a e di b.
!43
Corso sul Linguaggio C++ Edizione 2010
Per questo la prima cosa che il computer deve fare e procurarsi i valori dei coefficienti a e b.
Dopo, se a è diverso da zero, deve calcolare e visualizzare la soluzione, altrimenti visualizza
la frase "Equazione impossibile!" se b è diverso da zero oppure "infinite soluzioni" se b è
uguale a zero. Il semplice programma che fa fare queste cose al computer è il seguente:
#include <iostream.h>
#include <stdlib.h>
// Programma Eqaz1 : Soluzione delle equazioni di primo grado
int main()
{
float a,b,x;
cout << "Inserisci i due coefficienti: ";
cin >> a; cin >> b;
if (a==0)
if (b==0) cout << "Equanzione indetrminata!\n";
else cout << "Equazione impossibile!\n";
else
{x= -b/a; cout << "\nLa soluzione è: " << x << endl;}
system("PAUSE");
return 0;
}
Si noti che quando due istruzioni if sono annidate, come nell’esempio precedente, il primo
else che si trova si riferisce sempre all’ultimo if, perché prima di proseguire l’istruzione if
esterna bisogna completare quella interna.
Quello che segue è il diagramma a blocchi corrispondente al programma.
Inizio
Scrivi “Inserisci i coefficienti:”
Leggi a,b
a == 0
Si
x = -b/a
b == 0
Scrivi x
Scrivi “Equazione impossibile!”
Si
Scrivi “Equazione
indeterminata!"
Fine
!
3.5.Selezione multipla
La selezione si utilizza quando in un algoritmo c’è un gruppo di azioni che deve essere eseguito solo in un determinato caso. Se i casi possibili, e i relativi gruppi di azioni, sono due utilizza la selezione a due vie. Se i casi sono più di due si possono utilizzare le istruzioni if annidate:
If (caso == 1)
{ \\ primo gruppo di istruzioni
…………
}
!44
Corso sul Linguaggio C++ Edizione 2010
else
if (caso == 2)
{ \\ secondo gruppo di istruzioni
…………
}
else
if (caso == 3)
{ \\ terzo gruppo di istruzioni
…………
}
ma per questo tipo di algoritmi la maggior parte dei linguaggi di programmazione mette a disposizione anche un’istruzione apposita, quella per la selezione multipla, che per il linguaggio
C++ è l’istruzione switch. La sintassi è la seguente:
istruzione switch
(
switch
espressione numerica
)
{
blocco switch
}
blocco switch
case
costante
:
istruzione
default
!
:
istruzione
L’espressione numerica in base alla quale viene effettuata la scelta deve essere di tipo intero
(quindi può essere anche di tipo char). Il computer valuterà l’espressione e poi farà proseguire
il programma dal punto in cui c’è scritto case x: con x = risultato dell’espressione. Se non c’è
nessuna costante nel blocco switch che corrisponde al risultato dell’espressione verranno eseguite le istruzioni poste dopo la parola chiave default, se non c’è nemmeno la clausola default il controllo passa all’istruzione successiva al blocco switch. La traduzione di questo costrutto in linguaggio macchina è più efficiente rispetto alla traduzione degli if annidati. Se fra
i vari gruppi di istruzioni possibili ne deve essere eseguito solo uno, bisogna utilizzare anche
l’istruzione break che fa saltare il punto di esecuzione all’istruzione successiva al blocco
switch saltando quindi tutte le istruzioni rimanenti inserite nel blocco.
Per esempio se vogliamo tradurre con l’istruzione switch le istruzioni if annidate viste all’inizio di questo paragrafo dobbiamo scrivere:
switch (caso) {
case 1:
// primo gruppo di istruzioni
…………
break
case 2:
// secondo gruppo di istruzioni
…………
break
case 3:
// terzo gruppo di istruzioni
…………
}
Problema: una semplice calcolatrice
Vogliamo fare un programma per realizzare una semplice macchina calcolatrice che fa le 4
operazioni fondamentali. Il computer deve leggere due numeri, chiedere quale operazione effettuare (+, -, *, /) e visualizzare il risultato.
Il programma potrebbe esser il seguente:
!45
Corso sul Linguaggio C++ Edizione 2010
#include <iostream.h>
#include <stdlib.h>
/* programma SCalc: Una semplice calcolatrice */
int main()
{double a,b; char op;
cout << "Inserisci il primo operando: "; cin >> a;
cout << "Inserisci il secondo operando: "; cin >> b;
cout << "Quale operazione (+ - * /)? "; cin >> op;
switch (op) {
case '+': cout << "Risultato = " << a+b << endl; break;
case '-': cout << "Risultato = " << a-b << endl; break;
case '*': cout << "Risultato = " << a*b << endl; break;
case '/': cout << "Risultato = " << a/b << endl; break;
default : cout << "Errore! bisogna inserire uno dei segni + - * /\n";
}
system("PAUSE");
return 0;
}
Mandandolo in esecuzione e provando, per esempio, la moltiplicazione tra i due numeri 5 e 3
si ottiene:
Inserisci il primo operando: 5
Inserisci il secondo operando: 3
Quale operazione (+ - * /)? *
Risultato = 15
Premi un tasto per continuare ...
3.6.I cicli
Il principale vantaggio che ha un computer rispetto ad un essere umano nell’eseguire un compito è la velocità di esecuzione. Un personal computer, per esempio, è in grado di eseguire
qualche centinaio di milioni di operazioni aritmetiche al secondo, cosa che nessun essere
umano è in grado di fare. Però per fargli eseguire una operazione bisogna dargli il comando
opportuno e per fargli eseguire più operazioni bisogna scrivere un programma dove sono
elencati i comandi per ciascuna operazione. Per fortuna anche se il computer esegue milioni
di operazioni al secondo non è necessario scrivere programmi con milioni di istruzioni per
ogni secondo di elaborazione, infatti la maggior parte dei programmi contiene relativamente
poche istruzioni che però vengono fatte eseguire più volte, in alcuni casi anche milioni o miliardi di volte. Per far risolvere un problema complesso al computer bisogna spesso progettare
un procedimento che preveda la ripetizione meccanica di una serie di azioni semplici e questo
è un modo di affrontare i problemi a cui noi umani non siamo abituati. Per questo motivo le
istruzioni per i cicli, cioè quelle che servono per far ripetere una serie di azioni al computer,
sono molto importanti in ogni linguaggio di programmazione. Il linguaggio C ha tre istruzioni
per i cicli: l’istruzione do (ripetizione postcondizionale), l’istruzione while (ripetizione precondizionale) e l’istruzione for (ripetizione con contatore).
Istruzioni do e while
Entrambe le istruzioni do e while servono per far ripetere una serie di azioni fin quando la condizione
prefissata è vera, appena la condizione diventa falsa il ciclo termina. La differenza sta solo nel momento in cui la condizione viene valutata, nel caso del do la condizione viene controlla solo dopo l’esecuzione dell’istruzione del ciclo mentre nel caso del while prima. Per questo motivo il ciclo do viene detto
postcondizionale mentre il ciclo while viene detto precondizionale. La condizione che viene valutata ogni volta nel ciclo può essere una qualsiasi espressione logica e quindi anche un espressione con
risultato intero (0 = falso, un numero diverso da zero = vero).
Le azioni eseguite dal computer nei due casi sono quelle esplicitate nel seguente diagramma a blocchi:
!46
Corso sul Linguaggio C++ Edizione 2010
istruzione
si
condizione
si
istruzione
no
condizione
no
A) ciclo while (precondizionale)
! B) Ciclo do (postcondizionale)
La sintassi delle due istruzioni è la seguente:
Istruzione do
istruzione
do
while
(
condizione
)
;
Istruzione while
while
!
(
condizione
istruzione
)
Per esempio con il seguente programma
int main()
{
int i=5;
do cout << i-- << "\t"; while (i>0);
system("PAUSE");
return 0;
}
l’istruzione cout << i-- < “\t” viene eseguita mentre la condizione i>0 è vera e quindi viene
ripetuta fin quando il valore di i arriva a zero. Il risultato in output sarà:
5
4
3
2
1
Premere un tasto per continuare
In questo caso se avessimo usato l’istruzione while invece di do il risultato non sarebbe cambiato. Cambia qualcosa tra do e while nei casi in cui la condizione è vera già la prima volta
che viene eseguita l’istruzione perché in questo caso con while il ciclo non viene eseguito
mentre con do viene eseguito sempre almeno una volta.
Istruzione for
Il più comune tipo di ciclo è quello in cui si fa ripetere dal computer una serie di azioni un numero prefissato di volte. Questo tipo di ciclo si può realizzare utilizzando un contatore che parte da zero e le
istruzioni do e while con la condizione per far continuare il ciclo impostata nel seguente modo:
contatore < numero volte che il ciclo deve essere ripetuto
Questo tipo di ciclo viene detto ciclo con contatore o ciclo enumerativo, considerato che è un tipo
di ciclo molto utilizzato, la maggior parte dei linguaggi di programmazione ha un’istruzione apposita
per esso: l’istruzione for.
La sintassi dell’istruzione for per il linguaggio C++ è la seguente:
Istruzione for
for
(
inizializzazione
C o n d izione
;
!
che corrisponde al seguente diagramma a blocchi:
!47
;
i n c r emento
)
istruzione
Corso sul Linguaggio C++ Edizione 2010
inizializzazione
condizione
falsa
vera
incremento
istruzione
! prosegue il programma
questo significa che, prima di tutto viene eseguita l’istruzione di inizializzazione, poi inizia il
ciclo e viene valutata la condizione (quindi si tratta di un ciclo precondizionale), poi, se la
condizione è vera, viene eseguita l’istruzione e l’incremento che è l’ultima operazione del ciclo. Per esempio se vogliamo far scrivere dieci volte su video la parola “ciao” basta inserire la
seguente istruzione for:
for (int i=0; i<10; i++) cout << "ciao\n" ;
il computer prima crea la variabile i con zero dentro, poi inizia il ciclo in cui controlla se i<10
e, fin quando è vero, scrive ciao su video e incrementa i.
Da notare che quando l’istruzione di inizializzazione comprende anche la dichiarazione della
variabile come nell’esempio precedente, la variabile sarà creata appositamente per il ciclo e
poi cancellata alla fine del ciclo, quindi si tratterà di una variabile locale con area di validità e
ciclo di vita ristretta alle sole istruzioni del ciclo.
Se le istruzioni del ciclo sono più di una bisogna inserire un blocco al posto dell’istruzione del
ciclo. Per esempio supponiamo di voler scrivere il programma per far calcolare la media di n
numeri letti da tastiera, il programma può chiedere “Quanti numeri?” e poi eseguire un ciclo
per leggere i numeri e sommarli. Nel ciclo devono essere inserite più istruzioni, quelle per
leggere un numero e quella per sommare il numero letto all’accumulatore:
#include <iostream.h>
#include <stdlib.h>
// Programma media. Calcola la media di una serie di numeri in input
int main()
{ float somma=0, num, media; int i,n;
cout << "Quanti numero? "; cin >> n;
for (i=0; i<n; )
{cout << "inserisci il numero " << ++i << ": "; cin >> num;
somma += num;}
media = somma / n;
cout << "La media e' = " << media << endl;
system("PAUSE");
return 0;}
In questo caso l’istruzione di incremento è stata omessa perché conveniva includerla tra le
istruzioni del ciclo:
cout << "inserisci il numero " << ++i << ": « ;
si noti l’uso della notazione prefissa (++i) che produce in output il risultato dell’incremento.
Mandando in esecuzione il programma con tre numeri in input (3, 5, 6) si ottiene in output :
Quanti numeri ? 3
Inserisci il numero 1: 3
Inserisci il numero 2: 5
Inserisci il numero 3: 6
La media e’ = 4.66667
Premere un tasto per continuare ...
!48
Corso sul Linguaggio C++ Edizione 2010
Con tutti i tipi di cicli si possono usare anche le istruzioni di salto break e continue.
L’istruzione break interrompe l’esecuzione del ciclo e fa proseguire il programma con l’istruzione successiva al ciclo.
L’istruzione continue interrompe l’iterazione corrente senza completare le istruzioni presenti
nel corpo del ciclo e, a differenza di break, fa proseguire il ciclo con l’iterazione successiva,
nel caso del ciclo for il punto di esecuzione passa all’istruzione di incremento che è l’ultima
istruzione del ciclo, nel caso dei cicli do e while passa al controllo della condizione.
Problema numeri primi
Visualizzare i numeri primi compresi tra due limiti a e b dati in input.
I numeri primi sono quelli divisibili solo per 1 e per se stesso. Si può dimostrare che per vedere se un numero è primo basta controllare che non è divisibile per nessun numero compreso
tra 2 e la radice del numero. Per fare questo possiamo utilizzare un ciclo ma se ad un certo
punto troviamo un divisore è inutile continuare il ciclo fino alla fine perché già sappiamo che
il numero non è primo. Il programma è il seguente:
#include <iostream.h>
#include <stdlib.h>
#include <math.h>
int main(){
/* programma numprimi.
Visualizza tutti i numeri primi compresi tra due numeri a e b dati in
input*/
int a,b,p,i;
cout << "Inserisci il limite inferiore: "; cin >> a;
cout << "Inserisci il limite superiore: "; cin >> b;
for (p=a; p<=b; p++)
{for (i=2;i<= sqrt(p);i++) //se c'è un divisore <= sqr(p) ferma il ciclo
if (!(p % i)) break;
// se il ciclo non è stato fermato il numero p è primo
if (i > sqrt(p)) cout << p << " - ";
}
system("PAUSE");
return 0;
}
Per utilizzare la funzione sqrt (square root= radice quadrata) bisogna includere il file di header
math.h.
3.7.Documentazione
Il linguaggio C++ include poche operazioni e istruzioni base, molte altre sono disponibili in
librerie esterne in genere fornite insieme al compilatore del linguaggio, per utilizzarle bisogna
collegare le librerie che le contengono. Per esempio l’operazione radice quadrata ( x
=sqrt(x)) o la potenza (xy = pow(x,y)) sono incluse in una libreria a parte e devono essere dichiarate prima di essere utilizzate. Per inserire la dichiarazione di tutte le funzioni matematiche basta includere all’inizio del programma il file di intestazioni math.h. Per farlo si può utilizzare la direttiva:
#include <math.h>
La quantità di funzioni esterne incluse nelle librerie fornite insieme al linguaggio è molto elevata, un elenco di quelle standard del linguaggio C, fornite insieme al compilatore g++ incluso nel pacchetto dev-C++, si può trovare sul sito ufficiale dell’organizzazione gnu:
http://www.gnu.org/software/libc/manual
!49
Corso sul Linguaggio C++ Edizione 2010
Per avere informazioni sulle peculiarità del linguaggio C++ implementato nel compilatore g+
+ della GCC (Gnu Compiler Collection) incluso nel DEV C++ si deve visitare il sito:
http://www.gnu.org/software/gcc/onlinedocs/
purtroppo solo in lingua inglese.
Anche su Wikipedia trovate molte informazioni sul linguaggio C++ e sui compilatori disponibili. Trovate informazioni e spiegazioni anche per le librerie standard del C++ all’indirizzo:
http://en.wikipedia.org/wiki/C%2B%2B_Standard_Library
Per approfondire la conoscenza del linguaggio C++ un ottimo manuale è quello di Bruce Eckel, Thinking in C++, in due volumi, disponibile gratuitamente sul sito:
http://www.mindview.net/,
3.8.Esercizi
18) Individuare gli errori di sintassi nelle seguenti istruzioni:
a) cin >> a+2:
b) cout >> “Prova”;
c) FOR(a=1, a>10, a++);
d) a=b=c
19) Siano dati i seguenti cicli:
a) for (i = 0; i<n; i=i+2) ;
b) for (i = 0; i<n; i++) {i++; i++;}
c) i=n/2; while (i < n) i *=2;
d) i=n; do i-=n/2; while ( i >=0);
Completare la seguente tabella indicando quante volte verrà eseguito il ciclo ed il valore della
variabile i alla fine dello stesso supponendo che la variabile n = 10
Ciclo
N° di volte
Valore di i
a)
b)
c)
d)
20) Completare la tabella indicando cosa conterrà la variabile C dopo l'esecuzione delle seguenti istruzioni if annidate tenendo conto dei valori iniziali di A e B indicati nelle prime
due colonne:
if (A + B >10)
if (A > 10 && B < 10) C=A - B; ELSE C=A - B - 100;
else
if (A < 0 || B < 0) C= A + B; ELSE C= A - B + 100;
A
B
10
20
-10
-20
C
!50
Corso sul Linguaggio C++ Edizione 2010
5
4
60
-10
21) Cosa fa il seguente frammento di programma?
int i=0;
while(i<50)
{if (i%2) cout << i << “\t”; i++;}
22) Considerate il seguente frammento di programma:
t=-1;
for (i=1; i<=n; i++) if (f(i)) t=i;
if (t>=0) cout << t ;
Quale delle seguenti affermazioni è corretta?
a) Il programma cerca e stampa il più piccolo intero x fra 1 e n tale che f(x)!=0; se tale
intero non esiste, il programma entra in un ciclo infinito.
b) Il programma cerca e stampa il più grande intero x fra 1 e n tale che f(x)!=0; se tale
intero non esiste, il programma entra in un ciclo infinito.
c) Il programma cerca e stampa il più piccolo intero x fra 1 e n tale che f(x)!=0; se tale
intero non esiste, il programma non stampa nulla.
d) Il programma cerca e stampa il più grande x fra 1 e n tale che f(x)!=0; se tale intero
non esiste, il programma non stampa nulla.
23) Cosa scrivono in output i seguenti cicli?
a) for (int i=1; i<7;i++) cout << i %5<<’ ‘;
………………………………………….
b) for (int i=1; i<7;i++) cout << i*2-1 <<’ ‘;
………………………………………….
c) int i=10; do {cout << i<<’ ‘; i -=5;} while (i>0); ………………………………………
d) int j=5,i=5; while(i>0) {cout << j <<’ ‘; if (i%2) j +=i else j-=i; i--;} ….……………..
24) Considerate il seguente frammento di codice:
float i,f;
...
f=1/50.0;
for (i=0.0; i!=1.0; i+=f) printf("A");
Quale dei seguenti effetti ha il ciclo for indicato?
a)Stampa 50 volte il carattere A;
b)Stampa 51 volte il carattere A;
c)Stampa 49 volte il carattere A;
d) Il ciclo potrebbe non terminare, stampando infinite volte il carattere A; e)Il compilatore segnala un errore;
Solo selezione
25) Data la misura dei tre lati di un triangolo dire se è isoscele scaleno o equilatero.
26) Un lanificio acquista lana dai pastori della zona. La lana acquistata è di tre tipi diversi
(che si acquistano a prezzi diversi), il prezzo inoltre cambia in base all'umidità, se questa
supera il 30% il prezzo di acquisto si riduce del 15%. Fare un programma che aiuti
l'impiegato a calcolare la somma da versare ai pastori che portano la lana.
27) Una cooperativa agricola vende ai propri soci il vino che produce al prezzo di € 1 al litro
se bianco, 1.5 se rosso e 2 se D.O.C. E' possibile prendere il vino sfuso o imbottigliato, in
questo secondo caso il prezzo aumenta ulteriormente di €. 0.20 a litro. Descrivere un
programma per calcolare il prezzo del vino ogni volta che viene un cliente.
!51
Corso sul Linguaggio C++ Edizione 2010
28) Un commerciante, in un mese, ha acquistato merce per X lire e ne ha venduto per Y lire.
Sapendo che l'aliquota IVA sulla merce trattata è il 20% calcolare l'IVA da versare o l'IVA
a credito a fine mese.
29) Fare un programma per calcolare l'IRPEF su un reddito assegnato. L’IRPEF, in base alla
finanziaria 2007, si calcola così:
a.
b.
Se il reddito è inferiore o uguale a 15.000€ si calcola il 23% del reddito
se supera i 15.000 ma é inferiore a 28.001 si calcola il 23% sui primi 15.000 (=€.3450) + il
27% sulla parte eccedente i 15.000€.
c. Se supera i 28.000 ma è inferiore ai 55001€ l’imposta dovuta è data da 6960€ (pari al massimo dello scaglione precedente) + il 38% sulla parte di reddito eccedente 28.000€
d. d. d a 5 5 . 0 0 0 € f i n o a 7 5 . 0 0 0 € l ’ i m p o s t a è p a r i a € 1 7 . 2 2 0
(15000*0,23+13000*0,27+27000*0,38) + il 41% della parte di reddito eccedente 55.000€
e. e. oltre € 75.000 l’imposta è pari a 25420€ + il 43% della parte di reddito che supera 75000
euro.
graficamente gli scaglioni possono essere rappresentati così:
27%
23%
15000
!
38%
43%
41%
28000
55000
75000
43%
30) Far calcolare il prezzo di una quantità assegna di vino che costa € 2.1 al litro supponendo
che se si acquista una quantità >= 20 litri si ha diritto al 10% di sconto.
31) Data in input una cifra qualsiasi, dopo averla arrotondata alle decine (per eccesso o per
difetto a seconda che il resto superi 5 o no), indicare quanti biglietti da 10€, quanti da 50
€ e quanti da 100€ sono necessari per pagare la somma inserita in input utilizzando il minor numero possibile di biglietti.
Cicli
32) Dato in input un numero intero N calcolare N fattoriale.
33) Dato in input un numero qualsiasi x e un numero intero n positivo, calcolare il risultato di
xn.
34) Assegnati n e d calcolare la somma dei primi n termini della progressione geometrica di
ragione d: 1 + d + d2 + d3 + …. + dn
35) Assegnati n e d calcolare la somma dei primi n termini della progressione aritmetica di
ragione d:
1+ 2d+ 3d+ 4d+ …+ nd
36) Calcolare il prodotto di due numeri A e B interi effettuando solo addizioni.
37) Calcolare il quoziente e il resto della divisione tra due numeri interi A e B effettuando solo
sottrazioni.
38) Dato in input un numero intero qualsiasi controllare se è primo oppure no e visualizzare la
risposta.
39) Dati due numeri interi A e B trovare il minimo comune multiplo.
!52
Corso sul Linguaggio C++ Edizione 2010
40) Dati due numeri interi A e B trovare il massimo comun divisore con l’algoritmo di Euclide. Euclide ha dimostrato che, detti A e B due numeri interi con A>=B, se A è divisibile
per B allora MCD(A,B) = B altrimenti MCD(A,B) = MCD(B, A%B). In pratica si può
cercare il MCD tra due numeri più piccoli. Ripetendo questa operazione fino a quando i
due numeri diventano divisibili si trova il Massimo Comun Divisore.
41) Dato in input un numero intero N visualizzare la somma dei suoi divisori.
42) Calcolare la somma dei numeri interi da 1 a n (n in input): 1+ 2 + 3 + 4 + ….. + n (verificare che corrisponde a n*(n+1)/2)
43) Far calcolare la somma dei primi n termini (N in input) della seguente successione:
1+ ½+ 1/3+ ¼ + 1/5 + 1/6 + 1/7+ ……+ 1/n
44) Far calcolare la somma dei primi n numeri dispari e verificare che corrisponde sempre a
n*n
45) Scrivere le istruzioni per far visualizzare i primi n termini (n in input) delle seguenti successioni di numeri:
a) 2 4 6 8 10 12 14 ...
b) 1 -3 5 -7 9 -11 13 ...
c) 1 2 9 4 25 6 49 8…
d) 2 3 4 5 8 9 16 17 32 33…
46) Far visualizzare su video un menù con una serie di voci tipo quelle dell’esempio sottostante, chiedere la scelta e controllare che venga inserito un valore valido, visualizzare l’ozione corrispondente alla scelta, far terminare il programma quando viene scelta la funzione corrispondente a Fine.
Possibili scelte
1) Funzione 1
2) Funzione 2
3) Funzione 3
4) Funzione 4
5) Fine
Quale scegli?
47) Far calcolare la somma dei quadrati dei primi n numeri interi e verificare che corrisponde
a n*(n+1)*(2*n+1)/6
48) Far calcolare la somma della seguente successione di numeri interi:
1*N + 2*(N-1)+ 3*(N-2)+ …… +(N-1)*2 + N*1
si tratta di sommare una serie di prodotti di due numeri dove il primo fattore varia da 1 a N
mentre il secondo diminuisce da N a 1. (Questa somma, qualunque sia N è sempre = N*(N
+1)(N+2)/6 )
49) Far Calcolare la somma della seguente successione di numeri interi:
1*2 + 2*3 + 3*4 + 4*5 + …….. + (n-1)*n
il primo fattore va da 1 a n-1 mentre il secondo da 2 a N. (Questa somma è sempre uguale
a n*(n+1)(2*n-2)/6)
!53
Corso sul Linguaggio C++ Edizione 2010
50) Calcolare la somma della seguente successione e verificare che corrisponde a n*(n
+1)*(2*n+1)/3
n*(n+1) + (n-1)*(n+2)+ (n-2)*(n+3)+ ……….+ 2*(n+n-1) + 1*(n+n)
51) Far visualizzare la tabella dei codici ASCII.
52) Calcolare la somma della successione:
Nel ciclo fermarsi quando l’ultimo termine sommato è inferiore ad un numero E dato in
input.
in( x) = y −
y2
2
+
y3
3
−
y4
4
+
y5
5
+ ....
supponendo di avere in input x, con 0 <x < 2 e che y = x-1. Fermare il ciclo quando il valore assoluto dell’ultimo termine sommato è minore dell’errore E dato anch’esso in input.
Il risultato è il logaritmo naturale di x approssimato con un errore massimo = E.
53) Dato in input un numero intero n trasformarlo in binario.
54) Far visualizzare i primi n termini della successione di Fibonacci:
1; 1; 2; 3; 5; 8; 13; 21; ….. (ogni numero è la somma dei due precedenti e i primi due sono
entrambi = 1).
55) Dato in input un numero intero n e trasformarlo nel sistema di numerazione a base b (b in
input)
56) Dato un numero x scritto in un sistema a base b (x e b in input) trasformarlo in decimale.
57) Scrivere il programma che, dato in input x, calcoli la somma della seguente successione:
sen( x) = x −
x3
3!
+
x5
5!
−
x7
7!
+
x9
9!
+ ....
come si vede alcuni i termini vengono sommati o sottratti alternativamente. Il risultato, se
si continua all’infinito, è la funzione trigonometrica sen(x). Considerato che non si può
continuare all’infinito, fermarsi quando il valore assoluto dell’ultimo termine sommato è
minore dell’errore E dato in input (si può dimostrare che la somma di tutti i restanti termini è sempre minore del valore assoluto dell’ultimo termine sommato).
58) Come nell’esercizio precedente scrivere il programma che, dato in input un numero reale
cos(x) = 1 −
x2
2!
+
x4
4!
−
x6
6!
+
x8
8!
+ ....
x, calcoli la somma della seguente successione:
Sommando gli infiniti termini di questa successione si calcola la funzione coseno(x). Nel
ciclo fermarsi quando il valore assoluto dell’ultimo termine è minore dell’errore E dato in
input.
59) Come per gli esercizi precedenti far calcolare la somma della seguente successione (x in
input):
!54
Corso sul Linguaggio C++ Edizione 2010
ex = 1 + x +
x2
2!
+
x3
3!
+
x4
4!
+
x5
5!
+ ....
in questo caso viene calcolato ex, fermarsi quando si somma il termine n, tn = xn/n! con
n>x e abs(tn)*(n/(n-x))< E, dove E è l’errore massimo dato in input.
60) Scrivere un programma che dato in input un numero qualsiasi lo visualizzi invertendo
l’ordine delle cifre.
Doppio ciclo
61) Far visualizzare la tavola pitagorica fino ad un numero N assegnato.
62) Far visualizzare i primi n numeri primi (può essere utilizzato il programma per controllare
se un numero è primo oppure no).
63) Far calcolare X elevato a N utilizzando solo addizioni (si possono utilizzare i programmi
per fare la potenza e la moltiplicazione).
64) Far visualizzare tutti gli elementi della serie di Fibonacci (vedi esercizio 54) che siano anche numeri primi (composto dai due programmi Fibonacci + controllo numeri primi).
65) Scomporre un numero qualsiasi in fattori primi.
66) Assegnata una frazione A/B qualsiasi ridurla ai minimi termini
67) Cercare e far visualizzare tutti i numeri perfetti minori o uguali ad un numero N dato in
input. I numeri perfetti sono quelli per i quali la somma dei divisori (escluso il numero
considerato) è uguale al numero stesso, per esempio 6 (6=1+2+3) oppure 28
(28=1+2+4+7+14).
68) Scrivere un programma che faccia funzionare un computer come un registratore di cassa.
Deve permettere di inserire i prezzi dei prodotti acquistati da ciascun cliente e stampare
lo scontrino. A fine giornata deve visualizzare il totale incassato, il numero degli scontrini emessi, l'importo delle vendite diviso per quattro categorie merceologiche: Alimentari,
Detersivi, Salumeria, Altro.
69) Assegnato N far visualizzare tutti i numeri primi minori di N che fanno parte della serie di
Fibonacci.
70) Far leggere una serie di numeri in input e fare la media solo dei numeri primi.
71) Far generare tutte le possibili combinazioni di risultati di 4 partite di calcio. (es; 1111,
111X, 1112, 11X1, 11XX, 11X2, 1121 ecc. Si tratta delle permutazioni con ripetizione di
3 elementi a 4 a 4. Si può, per esempio, usare il sistema di num. ternario incrementando
una variabile e trasformandola in ternario).
Risposte esercizi
Esercizio 18):
a) dopo >> ci deve essere una variabile e non un’espressione
b) dopo cout è permesso solo l’operatore <<
!55
Corso sul Linguaggio C++ Edizione 2010
c) Il linguaggio C++ è case sensitive, FOR non è la stessa cosa di for, inoltre
per separare l’istruzione di inizializzazione dalla condizione e dall’istruzione di
incremento bisogna usare il punto e virgola (;) e non la virgola.
d) manca il punto e virgola finale
Esercizio 19)
Ciclo
N° di volte
Valore di i
a)
5
10
b)
4
12
c)
1
10
d)
3
-5
Esercizio20)
A
B
C
10
20
-110
-10
-20
-30
5
4
101
60
-10
70
Esercizio 21): scrive su video tutti i numeri dispari minori di 50.
Esercizio 22) esatta d)
Esercizio 23)
a)
b)
c)
d)
for (int i=1; i<7;i++) cout << i %5<<’ ‘; …1 2 3 4 0 1 ……….…….
for (int i=1; i<7;i++) cout << i*2-1 <<’ ‘; ………………1 3 5 7 9 11 …………………………..
int i=10; do {cout << i<<’ ‘; i -=5;} while (i>0); …………10 5……………………………………
int j=5,i=5; while(i>0) {cout << j <<’ ‘; if (i%2) j +=i else j-=i; i--;} …5 10 6 9 7……………….. .
Esercizio 24) esatta d): il tipo double ha una rappresentazione interna in binario virgola mobile e un numero con la virgola tipo 1/50 potrebbe diventare periodico quando viene trasformato
in binario - anzi 1/50 è periodico in binario perché non danno luogo a numeri binari periodici
solo le frazioni che si possono rappresentare con un denominatore che è una potenza del 2 - e
quindi ha infinite cifre per cui non può essere rappresentato esattamente, questo significa che
sommando 50 volte 1/50 scritto in binario in maniera non esatta, probabilmente non otterremo
1 e quindi il ciclo potrebbe non finire mai perché non si verifica mai la condizione i=1.0 che
fa terminare il ciclo.
Esercizio 40) Il cuore del programma per trovare il MCD potrebbe essere il seguente:
if (A < B) {r=A; A=B; B=r;} // ordina i due numeri
r=A%B; while (r > 0) {A=B; B=r; r=A%B;}
MCD = B;
Esercizio 46) Il programma potrebbe essere il seguente:
int main(){
short int scelta=0;
/* ripete la visualizzazione del menù fino a quando non si sceglie la
funzione FINE */
do {
// visualizza il menù
system("CLS"); // cancella la finestra di output
cout << endl << "\t\tPossibili scelte" << endl;
cout << "\t\t1) Funzione 1"<< endl;
cout << "\t\t2) Funzione 2"<< endl;
cout << "\t\t3) Funzione 3"<< endl;
cout << "\t\t4) Funzione 4"<< endl;
cout << "\t\t5) Fine"<< endl;
!56
Corso sul Linguaggio C++ Edizione 2010
cout << "\n\n\t\t\tQuale Scegli (1-5)?" ;
cin >> scelta; // chiede la scelta
// visualizza messaggio di errore se la scelta non è valida
if (scelta <1 || scelta > 5) {
cout << "\n\t\tErrore! Inserire un numero da 1 a 5!\n";
system("PAUSE");
} else {
// esecuzione della funzione corrispondente
switch (scelta) {
case 1: cout <<"E' stata scelta la funzione 1\n"; break;
case 2: cout <<"E' stata scelta la funzione 2\n"; break;
case 3: cout <<"E' stata scelta la funzione 3\n"; break;
case 4: cout <<"E' stata scelta la funzione 4\n"; break;
}
if (scelta < 5) system("PAUSE");
}
} while (scelta != 5);
return 0;}
Esercizio 51) Si può sfruttare la compatibilità tra il tipo di dati char e il tipo int più il fatto che
l’istruzione cout visualizza una variabile char come carattere e una int come numero. Il programma potrebbe essere il seguente:
int i; char x;
for (i=1; i<=255; i++) {x = i; cout << i << '=' << x << '\t';}
cout << endl;
!57