Linguaggio C++ Un primo semplice esempio: Calcolo dello spazio di frenata di unautomobile...
-
Upload
eleonora-sasso -
Category
Documents
-
view
306 -
download
7
Transcript of Linguaggio C++ Un primo semplice esempio: Calcolo dello spazio di frenata di unautomobile...
Linguaggio C++
Un primo semplice esempio:Calcolo dello spazio di frenata di
un’automobile
Fondamenti
Si desidera determinare lo spazio (in metri)
necessario ad arrestare un’automobile viaggiante
ad una data velocità (in km/h), ipotizzando la
decelerazione costante ed uguale a 9,2 m/s2
1. Analisi del problema
Una prima rappresentazione in pseudocodice
potrebbe essere la seguente:
Richiedi la velocità iniziale in km/hCalcola lo spazio di frenataComunica il risultato in metri
{
}
2. Scrittura dell’algoritmo
Secondo il metodo d’analisi TOP-DOWN, ogni fase
può essere considerata un sottoproblema e pertanto
elaborata ulteriormente. Mentre la prima e l’ultima
fase sono in una forma sufficientemente semplice,
per scomporre la fase Calcola lo spazio di
frenata è necessario conoscere le leggi della
cinematica relativa ai moti uniformemente
decelerati
Il modello matematico (formula) che descrive il
fenomeno del moto decelerato è il seguente:
d
vs i
2
2
1
dove:s è lo spazio necessario all’arresto (in metri)vi è la velocità iniziale (in m/s)
d è la decelerazione (9,2 m/s2)
Nel nostro caso, per poter applicare la formula
precedente è necessario convertire la velocità
iniziale da km/h a m/s. Chiamando viKmh la velocità
in km/h e con vi quella in m/s si ha:
6,3iKmh
i
vv
In conclusione, la fase Calcola lo spazio di
frenata può essere vista come:
Conversione della velocità da km/h a m/sCalcolo dello spazio
{
}
Calcola lo spazio di frenata
e, in ulteriore dettaglio:
2,92
1
6,32i
iKmhi
vs
vv
Calcola lo spazio di frenata{
}
L’algoritmo complessivo rimane comunque molto
semplice, la sola struttura di controllo utilizzata è la
SEQUENZA. Si vedrà adesso come si passa
dall’algoritmo (in questo caso in pseudocodice) al
programma in linguaggio C++
Ogni programma C++ deve sempre avere una (ed
una sola) funzione main dalla quale inizia
l’esecuzione del programma:
3. Scrittura del programma
int main()
...
...
{
}
Per funzione s’intende un insieme di dati ed
istruzioni, delimitato da una parentesi graffa aperta
{ e da una parentesi graffa chiusa }, cui è associato
un nome e che ritorna un valore. Si noti la notevole
somiglianza con la struttura utilizzata nel linguaggio
di progetto per definire un algoritmo. La parola int
che precede il nome della funzione indica che il
valore ritornato è un intero.
La traduzione del primo enunciato del nostro algoritmo:
Richiedi la velocità iniziale in km/h
sottintende, implicitamente due fasi distinte:
1. deve essere presentato sullo schermo un messaggio esplicativo affinché l’utente sia a conoscenza di quale dato richiede il programma in quel momento. Ad esempio:
Scrivi la velocita' iniziale [km/h]:
2. Il dato deve essere effettivamente acquisito e memorizzato al fine di poterlo utilizzare in un momento successivo.
Il linguaggio C++ non possiede alcuna istruzione
per la comunicazione e l’acquisizione dei dati ma,
insieme al compilatore, vengono solitamente fornite
un insieme di oggetti e funzioni che consentono di
supplire a questa mancanza. Questo insieme prende
il nome di Libreria Standard
In particolare, l’oggetto cout (console output) consente di interagire con l’unità di output standard
ovvero il video, e l’oggetto cin (console input) con l’unità di input standard, la tastiera. Scrivendo
il seguente programma:
int main(){
}
#include <iostream>
cout << "Scrivi la velocita' iniziale [km/h]: ";
using namespace std;
al momento dell’esecuzione sullo schermo comparirà il messaggio scritto tra virgolette
Il carattere punto e virgola (;) ha lo scopo di indicare al compilatore la fine dell’istruzione. Attenzione a non dimenticarlo altrimenti il compilatore interpreterà i caratteri successivi come appartenenti alla stessa istruzione, con risultati spesso imprevedibili
Le prime due righe del listato sono necessarie per interpretare e manipolare correttamente la successiva cout
cout rappresenta, simbolicamente, la destinazione standard dell’output (video) verso la quale è diretto il flusso (stream) delle informazioni presenti a destra del simbolo << ovvero dell’operatore di inserzione
A questo punto è necessario che il programma possa
acquisire e memorizzare il valore della velocità
dell’automobile.
In generale, per acquisizione s’intende l’operazione
mediante la quale un dato proveniente da un’unità
d’ingresso (in questo caso la tastiera) è memorizzato
in una variabile
Per variabile s’intende un'area circoscritta della
memoria RAM del calcolatore nella quale può
essere conservato un valore. Per semplicità, e per
potervi far riferimento quando occorre, ad ogni
variabile è associato un nome (identificatore)
In questo caso, ad esempio, la variabile che contiene
la velocità iniziale dell’automobile, espressa in km/h,
potrebbe essere chiamata arbitrariamente viKmh.
Nulla vieterebbe di chiamarla con un altro nome, ad
esempio x, ma è consigliato l’uso di un nome
mnemonico poiché permette di ricordare più
facilmente il dato che rappresenta
L’identificatore di una variabile non può essere
composto da caratteri qualsiasi ma deve essere una
sequenza di una o più lettere dell’alfabeto inglese
(maiuscole o minuscole), cifre e caratteri di
sottolineatura (underscore: _). Inoltre non può
iniziare con una cifra. Ad esempio sono corretti:
somma_numeri_Area3viKmh
Mentre non sono permessi identificatori come:
viKm/hvi Kmhvi-Kmh2vi
Il C++ distingue inoltre le lettere maiuscole dalle
minuscole (è case sensitive): identificatori con lo
stesso nome ma di formato differente sono
considerati nomi di variabili diverse
(il carattere / non è consentito)(lo spazio non è consentito)
(il carattere - non è consentito)
(non può iniziare con una cifra)
Un identificatore non può avere lo stesso nome e formato di una parola chiave (keyword) del
linguaggio. Questi identificatori predefiniti, infatti, hanno un significato speciale e non devono essere
confusi col nome attribuito alle variabili
Lo Standard prevede inoltre che le parole che
iniziano con un doppio underscore __ siano
riservate alle varie implementazioni del
compilatore.
L’insieme dei valori memorizzabili in una variabile
dipende in stretta misura dal modo in cui viene
rappresentata internamente e dal numero di byte
utilizzati. A tale proposito sono previsti dei tipi
fondamentali di variabili, ciascuno dei quali
consente di memorizzare dati appartenenti a insiemi
diversi (interi, reali e caratteri)
Nella tabella che segue è indicata la gamma dei
valori e l’insieme di appartenenza di alcuni tipi
fondamentali:
Tipo Gamma di valori Insieme
char -128 ÷ 127 Caratteri
int -2 147 483 648 ÷ 2 147 483 647 Interi
double -1,7976931410308 1,7976931410308 Reali
Per comunicare al compilatore la scelta del nome e
del tipo da utilizzare per una data variabile è
necessario una dichiarazione che, nella sua forma
più semplice, ha la seguente forma:
tipo identificatore;
Ad esempio, nel nostro caso, si potrebbe chiamare
la velocità iniziale dell’automobile viKmh e,
poiché è un valore appartenente all’insieme dei
numeri reali, associarle il tipo double:
double viKmh;
Le variabili vanno dichiarate prima di utilizzarle e le
dichiarazioni possono comparire ovunque. In questo
esempio viKmh è dichiarata prima della funzione main:
#include <iostream>
using namespace std;
double viKmh;
int main(){ ...}
A questo punto si può acquisire il valore della
velocità fornito dall’utente mediante la tastiera e
memorizzarlo nella variabile viKmh. Per farlo è
necessario fare ricorso ad un oggetto della Libreria
Standard, cin. L’oggetto cin è la sorgente
simbolica dei dati che provengono dall’ingresso
standard (la tastiera). L’operatore di estrazione >>
indica la direzione del loro flusso
#include <iostream>
using namespace std;
double viKmh;
int main(){ cout << "Scrivi la velocita' iniziale [km/h]: "; cin >> viKmh;}
Il primo enunciato dell’algoritmo, Richiedi
velocità iniziale dell’automobile in km/h,
potrà quindi essere tradotto nel seguente programma:
Si può adesso passare alla fase Calcola lo spazio di
frenata di cui riportiamo per comodità l’algoritmo:
2,92
1
6,32i
iKmhi
vs
vv
Calcola lo spazio di frenata{
}
La prima espressione:
6,3iKmh
i
vv
In C++ può essere scritta nel seguente modo:
vi = viKmh / 3.6
dove vi è un’altra variabile che sarà
opportunamente dichiarata di tipo double
Il formalismo è molto simile a quello delle normali
espressioni aritmetiche. Nel linguaggio C++ anche la
modalità di scrittura, così come i criteri adottati
nella valutazione delle espressioni, hanno origine
dall’aritmetica tradizionale
L’importanza delle espressioni nel linguaggio C++ è
rappresentata dal fatto che una qualsiasi espressione
terminata dal carattere punto e virgola ;
costituisce un’istruzione. L’azione che ne deriva
consiste semplicemente nella valutazione
dell’espressione
In generale, un’espressione è una combinazione
qualsiasi di operandi e operatori che dà origine a
un valore. Un operando è uno dei valori (costante o
variabile) che viene manipolato nell’espressione.
Poiché un operando possiede un valore, ne segue che
anche gli operandi sono espressioni
Quindi:
Sono tutte espressioni in quanto ognuna di esse
rappresenta un valore
viKmh
viKmh / 3.6
3.6
Gli operatori sono simboli (sia singoli caratteri che
loro combinazioni) che specificano come devono
essere manipolati gli operandi dell’espressione. Ad
esempio, nel rapporto:
viKmh e 3.6 sono gli operandi ed il carattere /
(slash) costituisce l’operatore di divisione
viKmh / 3.6
La valutazione di un’espressione avviene
eseguendo le operazioni indicate dagli operatori sui
loro operandi secondo le regole di precedenza degli
operatori, di norma uguali a quelle dell’aritmetica
tradizionale. Ad esempio, nell’espressione:
4 + 10 / 2
come consueto, sarà prima eseguita la divisione e poi l’addizione
Il segno = usato nell’espressione:
invece, ha lo stesso significato del segno
solitamente impiegato negli algoritmi per
rappresentare l’operazione di assegnazione.
Mediante questo operatore il valore a destra
dell’operatore = (r-value) è memorizzato
(assegnato) nell’operando di sinistra (l-value);
quest’ultimo, pertanto deve riferirsi a una locazione
di memoria modificabile
vi = viKmh / 3.6
È quindi lecito scrivere:
se x è il nome di una variabile, mentre sicuramente non avrebbe nessun senso il contrario:
x = 10
10 = x
perché 10 è un valore costante e non può essere modificato
È bene osservare che l’operatore di assegnazione non
ha lo stesso significato del segno uguale usato in
aritmetica. Pertanto, espressioni del tipo:
x = y e y = x
con x diverso da y, non sono assolutamente
equivalenti: nella prima il valore di y è
memorizzato nella variabile x; nella seconda,
invece, sarà il valore di x ad essere assegnato a y
Analogamente, mentre in aritmetica non è corretto
scrivere:
x = x + 5
in C++ è perfettamente lecito e assume il significato
di: somma alla variabile x il numero 5 e
memorizzane il risultato nella variabile x
Nell’espressione:
vi = viKmh / 3.6
compaiono quindi tre operandi e due operatori, quello
di assegnazione e quello di divisione. Poiché
quest’ultimo ha priorità maggiore del primo verrà
subito effettuata la divisione tra viKmh e 3.6 e,
successivamente, il risultato sarà memorizzato nella
variabile vi
2,92
1 2iv
s
s = 1 / 2 * vi * vi / 9.2
Si vedrà, adesso, come tradurre la seconda espressione dell’algoritmo Calcola lo spazio di frenata:
In C++ l’operatore di moltiplicazione si indica con l’asterisco *. Non esiste, invece, nessun operatore per
l’elevazione al quadrato. Pertanto, la suddetta espressione si scriverà:
1 / 2
Nonostante sembri corretta, il valore di questa
espressione sarà, tuttavia, sempre zero. Il perché di
questa singolarità sta nell’espressione:
Per valutare correttamente un’espressione, il
compilatore deve conoscere il tipo di ogni operando
coinvolto:
nel caso di variabili, il tipo è quello attribuitogli al
momento della loro dichiarazione; nel caso di
operandi costanti, invece, il tipo viene
automaticamente assegnato in base al loro valore e
come è stato specificato. Ad esempio le costanti:
10234-56789
vengono automaticamente assimilate a tipi int;
vengono considerate numeri reali: la prima eccede il massimo valore per una variabile di tipo int, la seconda è chiaramente un valore reale mentre la
terza, benché possa essere correttamente rappresentata da una variabile di tipo int, essendo stata specificata con una cifra decimale (anche se
zero), viene considerata un valore reale
mentre le costanti:
4567898586-567.489.0
In base a queste considerazioni, nell’espressione 1/2
le costanti 1 e 2 sono quindi interpretate come
operandi di tipo int.
L’operatore binario / effettua la divisione del primo
operando per il secondo. Se entrambi gli operandi
sono interi mentre il risultato della divisione non lo è,
il suo valore viene approssimato secondo le seguenti
regole:
1. Se entrambi gli operandi sono positivi o di
segno discorde, il risultato sarà troncato, cioè non
verranno considerate le cifre decimali.
2. Se entrambi gli operandi sono negativi,
l’approssimazione del risultato (troncamento
o arrotondamento) dipende dal compilatore
utilizzato
viene considerato come una divisione tra interi
positivi ed il risultato, ottenuto da quello reale
(0,5) per troncamento vale, pertanto, zero
Quindi, per le considerazioni precedentemente fatte,
il rapporto:
1 / 2
Il modo più semplice per ovviare a questo inconveniente è quello di trasformare una o entrambe
le costanti coinvolte in costanti reali, ad esempio:
1 / 2.0
Se gli operandi coinvolti in un’espressione sono
differenti, molti operatori effettuano
automaticamente delle conversioni per portarli ad
un tipo comune
Solitamente, durante questa operazione, l’operando di
tipo inferiore viene convertito in quello di tipo superiore
(che può rappresentare dei valori più alti).
Ad esempio nel rapporto precedente sono coinvolti un
operando di tipo intero (1) ed uno reale (2.0). Essendo
di tipo differente, prima della divisione, il primo (di tipo
inferiore) verrà automaticamente convertito nello stesso
tipo dell’altro, (di tipo superiore). Il risultato della
divisione sarà ancora del tipo comune, in questo caso un
reale
È possibile adesso aggiornare il programma che assume una forma quasi definitiva:
#include <iostream>
using namespace std;
double viKmh;double vi;double s;
int main(){ cout << "Scrivi la velocita' iniziale [km/h]: "; cin >> viKmh;
vi = viKmh / 3.6; s = (1 / 2.0) * (vi * vi) / 9.2; ...}
Per rendere più leggibile il programma, anziché
impiegare dei valori costanti è possibile usare delle
loro rappresentazioni simboliche. Ad esempio, in
questo problema la costante 9.2 rappresenta la
decelerazione. La formula che la contiene sarebbe
più chiara se al posto di 9.2 comparisse la lettera d
o la parola decelerazione
La dichiarazione di una costante simbolica è
analoga a quella di una variabile con la differenza
che è preceduta dalla keyword const. Poiché dopo
la dichiarazione non è possibile modificare una
costante, il suo valore deve essergli attribuito in
quell’occasione:
const double decelerazione = 9.2;
Da questo momento in poi, al posto del valore 9.2 è
possibile impiegare il nome simbolico
decelerazione. Eventuali espressioni del
programma che tentano di alterare il valore di
decelerazione saranno segnalate come errori in
fase di compilazione perché non è possibile
modificare il valore di oggetti dichiarati costanti:
decelerazione = 5.6;
A questo punto, manca solo la traduzione
dell’algoritmo Comunica il risultato in metri.
Può essere fatta utilizzando ancora l’oggetto cout
che consente di presentare sullo schermo dati e
messaggi combinati insieme. Se il valore
memorizzato nella variabile s è 48.5, scrivendo:
cout << "Lo spazio per il suo arresto e' di "
<< s << " metri" << endl;
sullo schermo apparirà:
Lo spazio per il suo arresto e' di 48.5 metri
endl, presente al termine dell’istruzione, è un
manipolatore di cout e serve a terminare la linea
introducendo un ritorno a capo. In questo caso,
eventuali altre operazioni di input/output sul
videoterminale inizieranno nella riga successiva
Infine, ecco il listato completo del programma:#include <iostream>
using namespace std;
double viKmh;double vi;double s;const double decelerazione = 9.2;
int main(){ cout << "Scrivi la velocita' iniziale [km/h]: "; cin >> viKmh;
vi = viKmh / 3.6; s = (1 / 2.0) * (vi * vi) / decelerazione;
cout << "Lo spazio per il suo arresto e' di " << s << " metri" << endl;
}
Benché questo programma risulti sostanzialmente
corretto, al fine di aumentarne la leggibilità da
parte di altri programmatori (ed anche di noi stessi,
dopo un certo periodo di tempo), è bene dotarlo di
appositi commenti che lo documentino in modo
appropriato
In un programma C++ il modo più semplice per
inserire un commento è di farlo precedere dal
doppio slash //. Tutto quello che viene scritto da
quel punto fino al termine della riga è considerato
un commento:
double s; // spazio di frenata in metri
Se il commento è molto lungo ed occupa più righe (ad
esempio per illustrare una parte del programma), è
conveniente impiegare una sintassi alternativa dove il
commento inizia con la sequenza di caratteri /* e
termina con la medesima sequenza, ma invertita, */:
/*Questo programma calcola lo spazio (in metri)
necessario ad arrestare un’automobile viaggiante ad
una data velocità (indicata in km/h) supponendo che
la decelerazione sia costante.*/
All’interno di un commento è ammesso qualunque
carattere (anche //) con l’esclusione della
combinazione */ che determina la fine del
commento stesso.
Diversamente dal commento che inizia col doppio
slash, la sintassi precedente consente di introdurre un
commento anche all’interno di un’espressione, ad
esempio:
Vi = viKmh / /* fattore di conversione */ 3.6;
I commenti non influenzano né la dimensione né la
velocità del programma eseguibile. È bene quindi,
utilizzarli frequentemente al fine di rendere più
leggibile un programma. Spesso in un programma
ben scritto, i caratteri utilizzati per i commenti sono
addirittura maggiori di quelli utilizzati per le
istruzioni
Affinché il programma appena scritto possa essere
eseguito, è necessario prima tradurlo in una forma
comprensibile al calcolatore. Questo compito può
essere svolto da appositi programmi che fanno parte
del cosiddetto software di base. I passi da seguire
possono essere schematizzati dal diagramma di
flusso che segue:
Programmasorgente
Editor
Compilatore
Linker
Librerie
Programmaeseguibile
Esempio: programma per ilcalcolo dello spazio di frenata
File sorgenteEsempio:
frenata.cpp
.obj
.lib
File eseguibileEsempio: frenata.exe
I programmi descritti possono differire a seconda
delle implementazioni.
Esistono anche delle versioni che racchiudono, nello
stesso ambiente di sviluppo, le funzionalità di tutti
questi strumenti. Esempi tipici sono gli ambienti IDE
(Integrated Development Enviroment) Microsoft
Visual C++ .NET, Dev C++ e Borland C++ Builder