Linguaggio C++
Il C++ è uno dei linguaggi di programmazione più diffusi; è noto per le
sue caratteristiche di efficienza e flessibilità; è stato ideato nel 1979 dal danese
Bjarne Stroustrup presso i Bell Labs della Nokia.
Come si può intuire dal nome si tratta di un'estensione del suo progenitore : il linguaggio
C, introdotto nel 1972 da Dennis Ritchie, ricercatore della maggior compagnia
telefonica americana AT&T.
Il C++ mantiene tutte le virtù del C, ovvero è uno strumento pratico e funzionale,
versatile e potente, adatto a realizzare applicazioni di qualsiasi tipo
dotato della possibilità di interagire direttamente con le risorse hardware
della macchina, ma con una struttura della sintassi tipica dei linguaggi
di programmazione di alto livello. Questo elevato grado di compatibilità
con il C (di cui conserva semantica e sintassi) consente al programmatore
C++ di passare progressivamente dalla programmazione strutturata/procedurale
alla programmazione orientata agli oggetti (OOP Object Oriented Programming)
senza la necessità di riscrivere da capo tutto il codice esistente, riutilizzando
gli innumerevoli programmi e librerie già esistenti.
Per spiegare successo che C++ ha avuto nel corso del tempo si possono fornire le seguenti motivazioni.
● Tutti i problemi affrontabili in C sono anche in C++
● Gli ampliamenti introdotti rispetto al C rimediano le principali carenze del vecchio linguaggio.
● L'introduzione del nuovo standard ha migliorato la possibilità di scrivere applicazioni facilmente portabili su sistemi diversi.
● E' efficiente e di conseguenza viene utilizzato in tutte le situazioni dove la velocità di risposta diventa un fattore critico.
● Il C++ è uno dei più diffusi linguaggi di programmazione; questo vuol dire che sono già disponibile una quantità notevole di librerie, moltissimi segmenti di codice già pronte all'uso, un gran numero di driver e di periferiche, una bibliografia immensa, numerosi compilatori e debugger.
● E' uno tra i linguaggi più flessibili: con il C++ si può scrivere praticamente qualsiasi software, da sistema operativo alla piccola applicazione.
● Essendo uno dei linguaggi più conosciuti e usati dai programmatori, ha dei compilatori molto affidabili e i programmi che ne risultano sono stabili(sempre che siano scritti correttamente) e veloci in esecuzione, su tutte le piattaforme.
● E' un buon compromesso tra semplicità di scrittura del codice potenza e flessibilità.
● Per la sua grande diffusione, la sintassi e la semantica del C++ è stata scelta come base per altri linguaggi di programmazione (come il C# Java) o per linguaggi di scripting lato client (come JavaScript) e lato server (come PHP).
● Imparare il C++ significa possedere le basi per apprendere linguaggi più usati nella programmazione professionale.
Livelli di funzionalità di un computer
Nello schema seguente viene riportata la gerarchia dei livelli di funzionalità di un computer
Il livello software più basso corrisponde al linguaggio
macchina o assembler (o assembly).
A questo livello ogni "istruzione" corrisponde ad un numero binario. Il
codice binario è l'unico tipo di informazione che le macchine possono comprendere.
In realtà una macchina può solo distinguere tra ciò che è zero e tra ciò
che non lo è.
A livello immediatamente superiore troviamo il sistema
operativo. Il sistema operativo è il software di base che ci permette
di utilizzare le risorse del sistema:
1 Le periferiche di input/output
2 La RAM
3 Il microprocessore (CPU)
4 La gestione della memoria di massa (disco
fisso o hard disk)
Il sistema operativo è dunque un insieme complesso di programmi che interagendo tra loro svolgono una serie di funzioni fondamentali per consentire all'utente un utilizzo della macchina semplice ed economico.
A livello immediatamente superiore troviamo il
software di sviluppo; si tratta di un insieme di programmi che permettono
di sviluppare le applicazioni che vengono definite dal programmatore. Ne
fanno parte gli editor, i compilatori,
gli interpreti e i linker.
Si tratta di un insieme di programmi in grado di tradurre sequenze di istruzioni
formulate in un linguaggio di programmazione ad alto livello come ad esempio
il C++. Un linguaggio ad alto livello, contrariamente all'assembler, che
ècostituito da sequenze di numeri binari, è un linguaggio di più
facile comprensibile per l'uomo .
Particolare importanza in questo caso è la differenza
tra compilatori ed interpreti.
● Un interprete,
legge un'istruzione alla volta, la traduce in linguaggio macchina e la invia
alla CPU per l'esecuzione.
● Un compilatore,
legge tutto il programma e lo traduce in linguaggio macchina; di conseguenza,
quando il programma viene eseguito, esso parte direttamente in linguaggio
macchina. Il C++ è un linguaggio compilato.
La differenza fondamentale risiede nel fatto che mentre l'interprete traduce le istruzioni una alla volta, il compilatore esegue la traduzione di tutto il programma in una sola volta, rendendo l'esecuzione molto più veloce; inoltre l'interprete, deve sempre risiedere in memoria, diminuendone la capacità disponibile, ma rendendo estremamente veloci le modifiche apportate al programma. Viceversa il compilatore viene caricato in memoria solo durante la compilazione, in quanto durante l'esecuzione non è richiesta la sua presenza; ma ad ogni modifica del programma sorgente è necessario far eseguire una nuova compilazione.
I programmi applicativi sono i programmi utilizzati dall'utente per risolvere problemi ben delimitati in abito scientifico, grafico, commerciale, gestionale, di elaborazione del testo etc.. Il software di sviluppo serve per creare programmi applicativi.
Struttura di un programma C++
I passi da eseguire per la realizzazione di un programma scritto in linguaggio C++ sono schematizzati nel seguente disegno
La fase iniziale di editing consiste nella trascrizione al calcolatore del codice sorgente. Questa operazione può essere svolta mediante in semplice editor di testi puro, come il blocco note (notepad) di Windows. Il risultato di questa operazione sarà il salvataggio di un file comunemente chiamato file sorgente con estensione .cpp che può essere richiamato in seguito per eventuali modifiche.
Per la fase successiva occorre disporre di un compilatore C++. Esistono
molteplici compilatori e linker, alcuni come gcc su Linux consentono di
eseguire le operazioni dalla riga di comando del sistema operativo ma prevalentemente
si usano degli IDE (Integrated Developement System) che comprendono tutte
le funzionalità necessarie per produrre il file eseguibile a partire dal
codice sorgente direttamente editabile nell'IDE. I più famosi sono Microsoft
Visual C++ .NET, Dev C++ e Borland C++ Builder. Tutti i programmi realizzati
in queste pagine sono invece stati realizzati su IDE CodeBlocks
che utilizza il compilatore MingW32.
Il compilatore elabora il file sorgente e, se non rileva errori genera a
sua volta un file oggetto (.obj oppure .o). Quest'ultimo contiene il programma
scritto in linguaggio macchina ma non ancora direttamente eseguibile dall'elaboratore.
Nell'ultima fase toccherà al linker completare il programma aggiungendo
quelle parti di codice necessario al suo funzionamento, ad esempio quelle
relative alle istruzioni cin e cout
per l'input/output da reperire nel file di libreria <iostream.h>.
Il compito del linker è quello collegare il codice intermedio, prodotto
dal compilatore, con quello mancante ottenuto da apposite librerie per formare
finalmente il file eseguibile. Se il programma supera la fase di compilazione
(è, dunque, esente da errori) il linker viene richiamato automaticamente
dal compilatore stesso.
A quel punto il programma creato potrà essere eseguito tramite il sistema
operativo e la sua fase di esecuzione prenderà il nome di fase
di runtime.
La struttura generale dei nostri programmi può essere schematizzata nel
modo seguente:
Una delle cose più importanti da notare è il simbolo punto e virgola (;)
che viene usato come terminatore di ogni singola istruzione.
Non tutti i linguaggi di programmazione usano questa regola; Visual Basic
non la usa, Python non la usa.
I programmi più semplici, di tipo procedurale sono essenzialmente costituiti
da una o più funzioni. All'interno del file sorgente deve esserci almeno
una funzione main(). Le funzioni sono sempre dotate di parentesi tonde all'inizio
della loro scrittura, servono a specificare l'eventuale presenza di parametri
(argomenti) da elaborare.
Le funzioni possono restituire un valore al programma che le ha invocate,
in tal caso vanno precedute da un prefisso che specifica il tipo di dato
restituito, come nel seguente esempio dove viene restituito un valore di
tipo float cioè un numero con la virgola.
in tal caso, deve essere sempre presente l'istruzione return
che specifica il valore da restituire al programma chiamante che ovviamente
deve essere sempre dello stesso tipo indicato come prefisso al nome della
funzione. Alcuni compilatori in linguaggio C/C++ sono talmente fedeli a
queste definizioni che pretendono che per stessa funzione main() venga specificato
il tipo di dato da restituire. In questo caso basta accontentarli specificando
il tipo numerico intero.
Questo è sempre il comportamento di linguaggi fortemente tipizzati come
C/C++ o Java; molto meno rigidi possono essere altri linguaggi come JavaScript
che effettuano un controllo molto più lasco sui tipi di dati da elaborare
e per questo vengono chiamati linguaggi debolmente tipizzati.
Veniamo ai preamboli (nel codice sorgente di qualsiasi programma ci sono
sempre dei preamboli) la premessa più frequente è l'indicazione delle librerie
utilizzate come la #include<iostream>
Questa riga non è un'istruzione ma una direttiva al compilatore. Diversamente
dalle istruzioni le direttive non terminano col punto e virgola (;). Questa
direttiva ha il compito di avvisare il linker e il compilatore che saranno
necessarie istruzioni provenienti dal file di libreria standard iostream
che in questo caso corrisponde all'utilizzo delle istruzioni di cin
per permettere l'input da tastiera e cout per consentire
l'output a video.
Oggetti e funzioni della libreria standard appartengono ad un unico insieme
denominato spazio dei nomi (namespace) standard e sono distinti da tutti
gli altri identificatori per il fatto di essere preceduti dal prefisso std.
Teoricamente per usare un'istruzione cout bisognerebbe
scrivere std::cout e allo stesso modo si dovrebbe
fare per l'input da tastiera std::cin per evitare
di ripetere ogni volta questo identificatore viene utilizzata la direttiva
using secondo la seguente sintassi:
using namespace std;
In tal modo l'aspetto più consueto che assumeranno i nostri scritti sarà:
ma non è da escludere la necessità di utilizzare altre librerie come la
libreria math.h che contiene speciali funzioni come la pow(base,
esponente) per l'elevamento a potenza o la sqrt(radicando)
per l'estrazione della radice quadrata di un numero maggiore o uguale a
zero che può essere dichiarata subito dopo la iostream
con la sintassi:
#include<math.h>
Identificatori
Nel linguaggio C/C++ sono definiti identificatori i nomi tramite i quali è possibile far riferimento a variabili, funzioni e alri oggetti definiti dal programmatore. Un identificatore è costituito da uno o più caratteri, di cui il primo deve essere una lettera o un carattere di sottolineatura(underscore _), mentre i caratteri seguenti possono essere lettere, numeri o sottolineature. Il C++ consente l'utilizzo del simbolo '$' all'interno di un identificatore, ma non all'inizio.
corretto | non corretto |
conta | 1conta |
ver23 | un'id |
altro_id | altro.id |
Espressioni
Una espressione è una combinazione qualsiasi di operandi ed operatori
che dà origine ad un valore. Ogni valore (costante o variabile) presente
in un'espressione è un'operando. Le espressioni sono costruite a partire
da operatori, costanti e variabili, seguendo prevalentemente le legole generali
dell'algebra. Ciò nonostante, ci sono alcuni aspetti direttamente collegati
alla natura del linguaggio.Ad esempio
v/3.6
!0
4+6/2
Nel primo caso se v è una variabile espressa in km/h
l'espressione v/3.6 rappresenta la stessa velocità
in m/s.
Nel secondo caso è presente l'operatore di negazione (!)
permette di far commutare uno 0 in un 1.
Nel terzo caso si tratta di una semplice espressione numerica che fornisce
7 come risultato.
Input/output
In linguaggio C++ per consentire l'ingresso di dati da tastiera è possibile
usare in comando cin. Per effettuare l'output a video si usa il comando
cout, entrambi appartenenti alla libreria iostream.
Ad esempio, il tradizionale programma di test "Hallo World" può essere scritto
nel seguente modo:
#include<iostream>
using namespace std;
main(){
cout<<"ciao Mondo";
}//main
cout è la destinazione standard dell'output video
verso la quale è diretto il flusso (lo stream) delle informazioni presenti
a estra del simbolo << chiamato anche operatore
di inserzione.
L'istruzione cout, permette di presentare sullo schermo
dati e messaggi combinati assieme; ad esempio:
#include<iostream>
using namespace std;
main(){
int x=3;
cout<<"spazio percorso:"<<x<<" m";
}//main
produrrebbe come output a video la stringa
Queste istruzioni vengono spesso utilizzate in concomitanza del comando
endl che permette di andare a capo;ad esempio:
#include<iostream>
using namespace std;
main(){
int x=3;
cout<<"spazio percorso:"<<endl<<x<<"
m";
}//main
l'output prodotto a video, sarebbe:
al posto di endl può essere usato alternativamente il simbolo "\n"
di ritorno a capo secondo l'istruzione.
cout<<"spazio percorso:\n"<
L'oggetto cin è la sorgente simbolica dei dati provenienti
dall'ingresso standard che è la tastiera e deve essere sempre accompagnato
dall'operatore di estrazione >> .
Spesso i due comandi vengono scritti sulla stessa riga perchè contestuali
ad una richiesta di dati che viene fatta all'utente.
cout<<"inserisci lo spazio:";cin>>x;
printf
In alternativa agli stream per acquisire e comunicare dati è possibile
utilizzare le funzioni printf() e scanf()
della libreria standard, richiamabile tramite le direttive
#include<stdio.h> oppure #include<cstdio> . Ad esempio:
#include<cstdio>
using namespace std;
main(){
int eta;
eta=27;
printf("La mia eta' e' di %d anni\n",eta);
}//main
La prima linea di codice all'interno di main() è
int eta;
Questa riga dichiara una variabile chiamata eta e dice al compilatore che
si tratta di una variabile intera. In linguaggio C è necessario dichiarare
tutte le variabili prima di usarle. Il procedimento di dichiarazione implica
sia la specifica sia il nome della variabile che il suo tipo di dato. In
questo caso eta è di tipo int parola chiave che in C serve a dichiarare
dati di tipo intero con numeri che vanno da -32768 a 32767. La linea successiva
è
eta=27;
che è un'istruzione di assegnamento.Questa linea pone il valore 27 nella
variabile eta, anche questa istruzione termina col punto e virgola come
tutte le istruzioni scritte in C. L'istruzione:
printf("La mia età è di %d anni\n",eta);
Quest'istruzione è importante per due ragioni: la prima è che si tratta
di esempio di una chiamata ad una funzione. La seconda è che illustra l'uso
della funzione standard di uscita printf(). La linea è costituita da due
parti: il nome della funzione printf e i suoi due argomenti: la stringa
"La mia età è di %d anni\n" e la variabile eta. Nel C non ci sono funzioni
interne di input/output, queste funzioni sono invece fornite dalla libreria
standard contenute nel file di inclusione stdio.h (libreria cstdio) . Un
programma può (e deve) contenere funzioni scritte dal programmatore stesso
oltre a quelle provenienti daqlle librerie. In ogni caso chiamare una funzione
risulta piuttosto semplice: bisogna solo scrivere il suo nome e fornire
gli argomenti necessari.
L'istruzione printf() lavora in questo modo: il primo argomento è una stringa che può contenere sia caratteri che direttive di conversione: una direttiva di conversione inizia con il segno di percentuale. Quando il C trova %d sa che deve scrivere un intero in formato decimale. Il secondo argomento rappresenta il valore che deve essere mostrato, in questo caso coincidente con la variabile eta.Infine \n è una speciale direttiva di conversione che fa in modo che la funzione printf() torni a capo alla linea successiva, dopo aver visualizzato la stringa.La forma generale di printf() è:
printf("stringa di controllo",parametri);
La stringa di controllo contiene i caratteri che saranno mostrati sullo schermo, direttive di conversione che dicono alla printf() come mostrare gli argomenti rimanenti oppure entrambi. Le direttive di conversione principali sono le seguenti
codice | significato |
%d | visualizza un intero in formato decimale |
%f | visualizza un reale in formato decimale |
%c | visualizza un carattere |
%s | visualizza una stringa |
I seguenti esempi mostrano ancora l'uso della printf().
printf("%s %d","questa è una stringa",100); //__>questa
è una stringa 100
printf("questa è una stringa %d",100); //__>questa è
una stringa 100
printf("il numero %d è decimale, %f è reale",60,7.89); //__>il
numero 60 è decimale, 7.89 è reale
printf("%c%c %s -%x",'u','n'," numero in decimale ed in esadecimale:",10,10);
//__>un numero in decimale ed in esadecimale 10-A
printf(%s","SALVE\n");
//__>SALVE
E' necessario avere tanti argomenti quante sono le stringhe di conversione:
in caso contrario, sullo schermo saranno stampati caratteri senza senso.
scanf
La funzione scanf() è una delle funzioni di ingresso del C. La forma generale di scanf() è la seguente:
scanf("stringa di controllo",lista di parametri);
Anche se non è esatto, supporremo per non creare confusione, che la stringa
di controllo possa contenere solamente stringhe di conversione. Le direttive
%d e %f dicono rispettivamente
alla funzione scanf() di leggere un intero e un numero
con la virgola.
Per evitare problemi nell'esecuzione del programma, è indispensabile che
il numero delle direttive di conversionbe sia uguale a quello degli argomenti
della lista dei parametri. Nella lista dei parametri, un segno & precede
le variabili che devono ricevere i valori letti dalla tastiera.
Tipi di dati in C++
In C++ esistono cinque tipi di dati primari:
Tipo di dato | |
carattere | char |
intero | int |
reale | float |
doppia precisione | double |
Senza valore | void |
Le variabili di tipo char sono impiegate
per contenere valori in cui sono sufficienti 8 bit come le lettere del codice
ASCII 'A', 'B', 'C'.
Le variabili di tipo int possono contenere
numeri che non richiedono parte frazionaria.
Le variabili di tipo float e di tipo double
sono impiegate nel caso in cui siano necessari numeri con parte frazionaria
(cifre dopo la virgola) o numeri molto grandi.
La differenza fra questi due ultimi tipi è unicamente nella massima e nella
minima quantità che possono rappresentare.
Il tipo void è stato introdotto per aumentare
le possibilità di controllo sui tipi.
Esiste anche un altro tipo di dato: il bool
(booleano) che può assumere valore 1 o 0 (vero o falso) occupa soltanto
1 bit e viene spesso associato a variabili o condizioni logiche.
Operatori
Per operatore si intende un simbolo che indica delle manipolazioni logiche
e matematiche sui dati.
Gli operatori appartengono a tre classi
Operatori aritmetici .
Operatori relazionali .
Operatori logici .
Operatori aritmetici
Gli operatori aritmetici servono appunto ad eseguire operazioni matematiche:
operatore | azione |
- | sottrazione |
+ | addizione |
* | moltiplicazione |
/ | divisione |
% | resto della divisione tra interi |
-- | decremento unitario |
++ | incremento unitario |
-= | decremento finito |
+= | incremento finito |
Notiamo che applicando un operatore / ad un intero viene troncato il resto,
ad esempio 14/3 da come risultato 6 qualora si tratti di una divisione fra
interi. L'operatore % restituisce il resto di una divisione fra interi,
ma non può essere usato coi float o con i double. Esempio:
main(){
int x=10,y=3;
cout<<x/y; //visualizza 3 (quoto)
cout<<x%y; //visualizza 1 (resto)
}
Incremento e decremento
L'operatore incremento unitario ++ somma 1 all'operando, mentre l'operatore
decremento unitario - - sottrae 1 all'operando. Di conseguenza l' istruzione
x++; equivale all'istruzione x=x+1;
mentre l' istruzione
x--; equivale all'istruzione x=x-1;
L'operatore incremento finito funziona in modo analogo:
x+=5; equivale all'istruzione x=x+5;
mentre
x-=5; equivale all'istruzione x=x-5;
Operatori relazionali
Col termine "relazionale" ci si riferisce alle relazioni che intercorrono tra i valori
operatore | azione |
> | maggiore |
>= | maggiore o uguale |
< | minore |
<= | minore o uguale |
== | uguale |
!= | diverso |
Operatori logici
Col termine "logico" ci si riferisce al modo in cui le relazioni possono essere associate fra loro
operatore | azione |
&& | AND |
|| | OR |
! | NOT |
I costrutti fondamentali del linguaggio vengono descritti successivamente e sono riportati in questa pagina:
● istruzione
if
● istruzione
switch
● ciclo
for
● ciclo
while
● ciclo
do-while
pochissime istruzioni che consentono di realizzare qualsiasi programma applicativo.