Introduzione al C++
Tipi integrali, conversioni di tipo,
costanti ed espressioni costanti,
direttive al preprocessore, inc...
Il concetto di tipo
• Determina i valori che può assumere una variabile e le operazioni
ammissibili su di essa
• Determina...
Il sistema dei tipi del C++
• Uno degli obiettivi principali del C++ è
permettere al programmatore di creare tipi
personal...
Cosa c’è da sapere di ogni tipo
• Che valori ammette
• Come sono rappresentati i valori nel calcolatore
– Sarebbe bello ig...
Inizializzazione delle variabili
• Le variabili si dichiarano e inizializzano
– La dichiarazione definisce il tipo
– L’ini...
Inizializzazione di default
(tipi predefiniti)
• Una variabile dei tipi predefiniti priva di inizializzatore
viene inizial...
Check this out!
• http://stackoverflow.com/questions/18870547/why-there-isno-difference-between-initialization-and-assignm...
I tipi predefiniti del C++
• I tipi aritmetici: integral e floating point
Il tipo bool
• Sta per Boolean (booleano)
• Rappresentare il tipo delle espressioni che il
programma usa per prendere deci...
Il tipo char
• Ammette come valore un singolo carattere
• Utilizza il minimo numero di bit necessario a rappresentare
l’in...
Il concetto di insieme di caratteri
• A differenza dei numeri
interi, i caratteri non hanno
una rappresentazione
“naturale...
Why character encoding matters

http://en.wikipedia.org/wiki/Mojibake
Insieme di caratteri ASCII
• Lo American Standard Code for Information
Interchange (ASCII ) è una codifica dei caratteri b...
ASCII Table
ISO 8859 (ISO LATIN)
•
•

•
•

I 95 caratteri ASCII stampabili
sono sufficienti per lo scambio di
informazioni in lingua i...
UNICODE, UTF-8, UTF-16
•
•

•

Unicode è un insieme di caratteri
e una sistema di codifica che
comprende oltre 110.000 sim...
I tipi int
• Approssima il dominio degli interi
• Normalmente utilizza 1 parola di memoria
• Esistono anche le varianti
– ...
La gestione del segno
• TUTTI i tipi integral, tranne bool, ammettono la
versione “senza segno” (unsigned)
• Il tipo norma...
Rapporto tra tipi signed e unsigned
• Tipi signed e unsigned non andrebbero mescolati
• Se si assegna un valore fuori inte...
Check this out
int main() { // Assegna a unsigned valore negativo
unsigned char c;
// va da 0 a 255;
cout << "Inserire un ...
Rapporto tra char e int
• In molti linguaggi di programmazione, char e int sono
tipi non solo diversi, ma incompatibili
• ...
Da char a int
• Determinare il codice di una lettera minuscola
• Cosa serve
– Una variabile char
– Una variabile int

• Al...
Da char a int
int main() {
// Legge un carattere e stampa il codice ASCII
char c;
// se è una minuscola; altrimenti termin...
Iterazione e condizione
• while (c >= 'a' && c <= 'z') {..
Corpo del ciclo..}
• Se la condizione è vera

• esegue le istru...
Da int a char
int main() {
// Stampa il codice carattere
char c;
// corrispondente ai 128 codici ASCII
for (int i=0; i<128...
Iterazione a conteggio
• for (int i=0; i<128; ++i)
• Quando una iterazione deve essere svolta un
numero preciso di volte s...
Ciclo while e ciclo for
char c;
for (int i=0; i<128; i++) {
c = i;
cout << “Il carattere
corrispondente a " << i
<< " è: "...
I tipi float e double
• Approssimano i numeri razionali
• I valori si possono rappresentare con due notazioni
– 315.779
– ...
Come rappresentare valori dei tipi
predefiniti

• Il valore 10 ha un tipo diverso da 10.0
• 10L è un valore di tipo long i...
Cautele
• Attenzione ai confronti tra float
float a, b;
...
if (a == b) ...

• non ha senso, a causa delle approssimazioni...
Check this out
• http://stackoverflow.com/questions/17333/m
ost-effective-way-for-float-and-doublecomparison
Quali tipi scegliere
• Usare tipi unsigned quando si è certi che servono
solo valori positivi
• Usare int per valori aritm...
Conversioni di tipo
• Se un operando non è del tipo atteso e il compilatore
non ha informazioni sul tipo desiderato interv...
La "scaletta" delle conversioni
Conversioni di tipo: esempi
int n, m;

float x,y;

n = 3.541 + 3; // il risultato è 6!
x = n;
x = n +
n = x;
n = n /
n = n...
Conversioni con il tipo bool
• Il tipo bool ha valore true o false
• I valori interi vengono convertiti a bool come segue
...
Conversioni con tipi un/signed
• Ecco perché è meglio non mescolare
unsigned u = 10;
int i = -42;
cout << i + i << endl; /...
Quando avvengono le conversioni
automatiche
• Nelle espressioni, i valori di tipi aritmetici piccoli vengono
solitamente p...
Altri esempi
bool b = 42; // b is true
int i = b; // i has value 1
i = 3.14; // i has value 3
double pi = i; // pi has val...
Conversione (cast) esplicita
• Quando una conversione utile non verrebbe
eseguita, la si può richiedere esplicitamente
• E...
ATTENZIONE
• Il cast (implicito o esplicito che sia) non modifica il
tipo della variabile o delle variabili coinvolte, ma ...
Le espressioni
•

Espressione: applicazione di operatori a
operandi
– Ha un valore e un tipo
– Condizione: espressione con...
Espressioni base
Le espressioni base si compongono di:
• Variabili
– Il tipo è noto in base alla dichiarazione, e NON camb...
Constanti di tipo stringa
"Hello World!" // string literal
•Ha un tipo composto che vedremo in seguito
– Array di const ch...
Espressioni e operatori
• Operatori unari: sia applicano a un operando
– -2

• Operatori binari: sia applicano a due opera...
Precedenza e associatività
•
•
•

•
•

Un'espressione con due o più operatori di dice composta
La sua valutazione richiede...
Ordine di valutazione operandi
• In generale l'ordine di valutazione di sotto-espressioni con
la stessa priorità NON è def...
Operatori aritmetici
• Precedenza e associatività (tutti associativi a sinistra)
• PS: % indica il resto delle divisione t...
Operatori logici e relazionali
• Sono usati per costruire condizioni, cioè espressioni
con valore di tipo bool

precedenza
La regola del cortocircuito
• Gli operatori AND e OR in C e C++ hanno un ordine di
valutazione prefissato (a differenza de...
L’operatore di assegnamento
• Anche = è un operatore!
• L’operando di sinistra deve essere una variabile (più
precisamente...
Esempi
int i = 0, j = 0, k = 0; // initializations, not
// assignment
1024 = k; // error: literals are rvalues
i + j = k; ...
ATTENZIONE
• Possiamo usare assegnamenti come condizioni e viceversa?
• Si, perché = è un operatore, proprio come ==
• Di ...
I costruttori di tipi
• A partire dai tipi predefiniti si possono creare
nuovi tipi, che aggiungono proprietà speciali ai
...
Il qualificatore const
• Talora serve definire una variabile che non cambi valore
• Per farlo si premette const alla dichi...
Visibilità delle variabili const
• const float pigreco = 3.14159265;

• Il compilatore sostituisce pigreco con il valore
a...
extern const
• Per definire una variabile const una sola volta, si usa la keyword
extern sia nella definizione che nelle d...
Definizione di macro: #define
• Esiste anche un altro modo di definire un valore una volta per tutte
– la direttiva #defin...
Definizione di macro: #define
• #define MIGLIO 1609.34
• #define YARDA
0.9144
• Si possono costruire MACRO a partire da al...
Altre direttive al precompilatore
• Abbiamo già visto:
#include <nome_libreria>
– Serve a richiamare librerie
– comanda al...
Esempio di programma multifile
/* File contenente funzioni di utilità sui cerchi
* dichiarazione e definizione di una cost...
File di intestazione della libreria
/*
*
*
*
*

File contenente solo le dichiarazioni delle
funzioni di utilità sui cerchi...
Programma principale
#include <iostream>
#include "pigreco.h"
using namespace std;
int main() {
float radius;
cout << "Ins...
I tipi definiti dall'utente
• La ragione principale del successo di C++ è che
consente di estendere il sistema dei tipi in...
Requisiti
• Si vuole costruire un programma che gestisca le
vendite di libri
• Ogni libro è caratterizzato da un codice IS...
Progettazione
• Inizializza il totale vendite a 0
• Leggi dati 1° transazione e aggiorna il totale
• Finché ci sono transa...
Suddivisione del programma
• Un file di libreria (Sales_item.h) conterrà la
definizione del tipo che rappresenta il dato d...
Un primo esempio di main()
#include <iostream>
#include "Sales_item.h"
int main()
{
Sales_item book;
// read ISBN, number ...
L'esempio completo
int main()
{
Sales_item total; // variable to hold data for the next transaction
// read the first tran...
Upcoming SlideShare
Loading in …5
×

05 2 integrali-conversioni-costanti-preproc-inclusione

804 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
804
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

05 2 integrali-conversioni-costanti-preproc-inclusione

  1. 1. Introduzione al C++ Tipi integrali, conversioni di tipo, costanti ed espressioni costanti, direttive al preprocessore, inclusione condizionale
  2. 2. Il concetto di tipo • Determina i valori che può assumere una variabile e le operazioni ammissibili su di essa • Determina la memoria minima necessaria per memorizzare una variabile • int: di solito una parola; float: di solito due parole • Permette al compilatore di rilevare errori nell'uso delle variabili – un linguaggio è fortemente tipizzato se garantisce: • correttezza delle istruzioni rispetto al tipo degli operandi, verificabile dal compilatore • che non sorgano errori di tipo in esecuzione • Il C++ persegue la tipizzazione forte – però è al tempo stesso molto permissivo, poiché ammette molte conversioni automatiche tra tipi diversi 2
  3. 3. Il sistema dei tipi del C++ • Uno degli obiettivi principali del C++ è permettere al programmatore di creare tipi personalizzati e usarli come se fossero offerti dal linguaggio • Il sistema dei tipi del C++ comprende – Tipi predefiniti (predefined) – Tipi composti (composite) – Tipi definiti dall’utente (user defined) – Tipi classe (class types)
  4. 4. Cosa c’è da sapere di ogni tipo • Che valori ammette • Come sono rappresentati i valori nel calcolatore – Sarebbe bello ignorarlo, ma talvolta non si può • Come rappresentare valori (costanti) di quel tipo nel programma (anche detti "literal") • Come dichiarare e inizializzare variabili di quel tipo • Quali operazioni sono ammesse sulle variabili • Quali tipi sono “affini” – Sono definite conversioni automatiche tra tipi affini
  5. 5. Inizializzazione delle variabili • Le variabili si dichiarano e inizializzano – La dichiarazione definisce il tipo – L’inizializzazione definisce il valore iniziale della variabile neonata – L’inizializzazione NON è l’assegnamento • quest’ultimo definisce il valore corrente della variabile • Alcune cose che si possono fare durante l’inizializzazione sono vietate nell’assegnamento int i = 0; tipo identificatore inizializzatore
  6. 6. Inizializzazione di default (tipi predefiniti) • Una variabile dei tipi predefiniti priva di inizializzatore viene inizializzata per default • Il valore di default dipende dal tipo della variabile e dalla posizione della dichiarazione – Variabili dei tipi predefiniti definite al di fuori di una funzione ricevono per default il valore 0 – Variabili dei tipi predefiniti definite all'interno di una funzione sono uninitialized, cioè il valore NON è definito • NB: per le variabili di tipo classe, il valore di inizializzazione per default può essere specificato dal programmatore
  7. 7. Check this out! • http://stackoverflow.com/questions/18870547/why-there-isno-difference-between-initialization-and-assignment-for-thebuild-im/articles/article.aspx?p=376876
  8. 8. I tipi predefiniti del C++ • I tipi aritmetici: integral e floating point
  9. 9. Il tipo bool • Sta per Boolean (booleano) • Rappresentare il tipo delle espressioni che il programma usa per prendere decisioni (se…, fintantoché…) • Ammette solo due valori: true e false – false è rappresentato tramite il valore numerico 0 – true è rappresentato da qualunque valore numerico diverso da 0 bool bool bool bool b b b b = = = = true; // b vale true 23; // b vale true false; // b vale false 0; // b vale false • In altre parole bool è un tipo (affine a) intero!
  10. 10. Il tipo char • Ammette come valore un singolo carattere • Utilizza il minimo numero di bit necessario a rappresentare l’insieme dei caratteri standard del calcolatore un byte (di solito 8 bit per rappresentare i caratteri ASCII) • I caratteri sono rappresentati internamente da numeri interi e quindi tra essi è definito un ordinamento – Esempio: il carattere '1' è rappresentato dall’intero 49, il carattere 'A' dall’intero 65, … • quindi, nell’ordinamento, risulta '1' < 'A' – Per le lettere è scelta una codifica tale per cui l’ordinamento dei codici coincide con l’usuale ordinamento alfabetico: 'A'<'B' ecc. • Lettere alfabeticamente adiacenti hanno codifiche adiacenti – Negli insiemi più usati le maiuscole latine sono codificate “prima” delle minuscole • Quindi ad esempio 'A'<'a' ma anche 'Z'<'a' 10
  11. 11. Il concetto di insieme di caratteri • A differenza dei numeri interi, i caratteri non hanno una rappresentazione “naturale” nel calcolatore • La rappresentazione è convenzionale e si ottiene “numerando” i simboli dell’insieme dei caratteri che si vuole rappresentare • Esistono molti insiemi di caratteri, che coprono un numero differente di simboli di lingue diverse • Gli insiemi di caratteri e le codifiche più usati sono – ASCII – ISO/IEC 8859 – UNICODE con UTF-8 e UTF-16
  12. 12. Why character encoding matters http://en.wikipedia.org/wiki/Mojibake
  13. 13. Insieme di caratteri ASCII • Lo American Standard Code for Information Interchange (ASCII ) è una codifica dei caratteri basata sull’alfabeto inglese che copre 27= 128 caratteri • Usa 7-bit • 95 caratteri stampabili: i numeri 0-9, le lettere a-z e AZ, simboli di punteggiatura e lo spazio bianco • Vari caratteri non stampabili, tra cui alcuni codici di controllo derivanti dalle Teletype machines
  14. 14. ASCII Table
  15. 15. ISO 8859 (ISO LATIN) • • • • I 95 caratteri ASCII stampabili sono sufficienti per lo scambio di informazioni in lingua inglese Molte altre lingue che usano l'alfabeto latino hanno bisogno di simboli addizionali, come la ß (tedesco), la ñ (spagnolo), la å (svedese e altre lingue scandinave) o le lettere accentate italiane (à, è, é, ì, ò, ù) L'ISO 8859 utilizza l'ottavo bit del byte, che permette la codifica di altri 128 caratteri ISO 8859 è organizzato in diverse parti: es: ISO 8859-1, Latin-1 Western European http://en.wikipedia.org/wiki/ISO/IEC_8859
  16. 16. UNICODE, UTF-8, UTF-16 • • • Unicode è un insieme di caratteri e una sistema di codifica che comprende oltre 110.000 simboli Unicode si sovrappone a ISO/IEC 8859-1, ma codifica inoltre i caratteri di quasi tutte le lingue vive e in alcune lingue morte, nonché simboli matematici e chimici, cartografici, l'alfabeto Braille, ideogrammi ecc. I caratteri Unicode sono rappresentati con le codifiche UTF-8 e UTF-16 • • UTF-8 (8-bit Unicode Transformation Format) è una codifica dei caratteri Unicode – usa un byte per i caratteri dell’insieme ASCII, che hanno lo stesso codice sia UTF-8 sia in ASCII, e fino a 4 bytes per gli altri caratteri (codifica a lunghezza variabile) UTF-16 (16-bit Unicode Transformation Format) è una codifica dei caratteri Unicode – può rappresentare fino a 1,112,064 entità (code points) tra cui i caratteri UNICODE da 0 a 0x10FFFF – La codifica è a lunghezza variabile, con uno o due unità da 16 bit
  17. 17. I tipi int • Approssima il dominio degli interi • Normalmente utilizza 1 parola di memoria • Esistono anche le varianti – short int, long int e long long int – tipico: long 32 bit, long long 64 bit, short 16 bit, e int 16 o 32 (per cui spesso int è grande quanto long int) • Lo standard del C++ richiede che – spazio per short <= spazio per int <= spazio per long <= spazio per long long
  18. 18. La gestione del segno • TUTTI i tipi integral, tranne bool, ammettono la versione “senza segno” (unsigned) • Il tipo normale permette di rappresentare numeri interi positivi e negativi • Il tipo unsigned permette di rappresentare solo numeri interi positivi, ma utilizza un bit in più (e quindi può rappresentare di più valori) – unsigned int: un valore intero positivo di almeno 16 bit, compreso tra 0 e 216-1 – Il prefisso signed si può omettere – unsigned èquivale a unsigned int – unsigned char  da 0 a 255
  19. 19. Rapporto tra tipi signed e unsigned • Tipi signed e unsigned non andrebbero mescolati • Se si assegna un valore fuori intervallo a una variabile di tipo unsigned, il risultato è definito come: – Il resto della divisione del valore per il massimo intero che il tipo unsigned può rappresentare • Per esempio, un tipo unsigned char da 8-bit rappresenta valori da 0 a 255. • L’assegnamento di un valore fuori intervallo dà come esito il resto di tale valore diviso per 256 – Assegnare –1 a un unsigned char da 8 bit produce il valore 255!
  20. 20. Check this out int main() { // Assegna a unsigned valore negativo unsigned char c; // va da 0 a 255; cout << "Inserire un numero negativo: " << endl; int i; cin >> i; cout << "Valore inserito (intero originale): " << i << endl; c=i; // assegno numero negativo a variabile char cout << "Valore inserito (char): " << c << endl; i=c; // recupero il valore intero di c cout << "Valore inserito (intero dopo la conversione a char): " << i << endl; return 0; } • Il compilatore non può rilevare l’errore • Non sa predire che valore inserisce l’utente • NB:
  21. 21. Rapporto tra char e int • In molti linguaggi di programmazione, char e int sono tipi non solo diversi, ma incompatibili • C e C++ considerano i caratteri come “una particolare interpretazione” dei numeri interi • La convertibilità tra char e int può portare a programmi difficili da comprendere • Usare char solo quando serve davvero una variabile che contenga un carattere, per esempio per – Cercare/contare/sostituire tutte le occorrenze di un carattere in un testo
  22. 22. Da char a int • Determinare il codice di una lettera minuscola • Cosa serve – Una variabile char – Una variabile int • Algoritmo 1. Leggi il prossimo carattere 2. Se è una lettera maiuscola 1. 2. 3. Convertilo in un intero Stampa il risultato della conversione Torna al punto uno 3. Termina
  23. 23. Da char a int int main() { // Legge un carattere e stampa il codice ASCII char c; // se è una minuscola; altrimenti termina int i; cout << "Scrivi un car. minuscolo (maiusc. x finire)" << endl; cin >> c; while (c >= 'a' && c <= 'z') { // minuscolo? i = c; // assegna il valore del carattere a un intero cout << "Valore ASCII per " << c << " è" << i << endl; cout << "Scrivi car. minuscolo (maiusc. x finire)" << endl; cin >> c; } return 0; // termina } NB: notare la ripetizione delle istruzioni che richiedono l'input
  24. 24. Iterazione e condizione • while (c >= 'a' && c <= 'z') {.. Corpo del ciclo..} • Se la condizione è vera • esegue le istruzioni all’interno del corpo • Quando la condizione è falsa • termina il ciclo (esce dal ciclo) • (c >= 'a' && c <= 'z') • • • • Esprime la condizione di permanenza nel ciclo E’ un’espressione con valore di tipo bool, cioè vero o falso && Operatore logico AND ‘a’ è un valore costante (literal) di tipo carattere
  25. 25. Da int a char int main() { // Stampa il codice carattere char c; // corrispondente ai 128 codici ASCII for (int i=0; i<128; ++i) { c = i; // assegna il valore intero al carattere cout << "Il carattere corrispondente a " << i << " è: " << c << endl; } return 0; }
  26. 26. Iterazione a conteggio • for (int i=0; i<128; ++i) • Quando una iterazione deve essere svolta un numero preciso di volte si può usare un “ciclo for” • Il ciclo incrementa una variabile apposita (contatore) per tener traccia del numero di interazioni – int i=0; dichiarazione del contatore – i<128; condizione di permanenza – ++i avanzamento del contatore
  27. 27. Ciclo while e ciclo for char c; for (int i=0; i<128; i++) { c = i; cout << “Il carattere corrispondente a " << i << " è: " << c << endl; } int i = 0; char c; while (i<128) { c = i; cout << “Il carattere corrispondente a " << i << " è: " << c << endl; i++; }
  28. 28. I tipi float e double • Approssimano i numeri razionali • I valori si possono rappresentare con due notazioni – 315.779 – 3.73E-5 • double di solito occupa più memoria di float – tipicamente 4 byte per float e 8 byte per double • (...esistono anche i long double, che devono occupare almeno tanto spazio quanto i double) • Lo standard prescrive la precisione minima, cioè il minimo numero di cifre significative 28
  29. 29. Come rappresentare valori dei tipi predefiniti • Il valore 10 ha un tipo diverso da 10.0 • 10L è un valore di tipo long int
  30. 30. Cautele • Attenzione ai confronti tra float float a, b; ... if (a == b) ... • non ha senso, a causa delle approssimazioni nella memorizzazione!! diff = A - B; if ((diff < EPSILON) && (-diff < EPSILON)); • EPSILON costante definita in std::numeric_limits
  31. 31. Check this out • http://stackoverflow.com/questions/17333/m ost-effective-way-for-float-and-doublecomparison
  32. 32. Quali tipi scegliere • Usare tipi unsigned quando si è certi che servono solo valori positivi • Usare int per valori aritmentici (short di solito non basta) • Se servono valori molto grandi usare long long • Non usare char e bool in espressioni aritmentiche – Se proprio proprio serve un intero piccolo usare signed char o unsigned char • Usare double per le operazioni in virgola mobile (di solito float ha precisione insufficiente e le operazioni sui double sono comunque veloci)
  33. 33. Conversioni di tipo • Se un operando non è del tipo atteso e il compilatore non ha informazioni sul tipo desiderato interviene una conversione automatica di tipo – È detta anche cast implicito – Si opera la conversione anziché segnalare l'errore • A volte è accompagnata da un “avvertimento” (warning) • Esempio – int i; float f; – la valutazione dell’espressione i + f effettua prima la conversione di i in float e poi la somma
  34. 34. La "scaletta" delle conversioni
  35. 35. Conversioni di tipo: esempi int n, m; float x,y; n = 3.541 + 3; // il risultato è 6! x = n; x = n + n = x; n = n / n = n / x = n / x = n / n da “int” è promosso a “float” x; // n è promosso a “float” e poi sommato a x // x è troncato, ne sopravvive la parte intera m; // il risultato della divisione tra interi è intero x; /* n è convertito in “float”, poi si esegue la divisione, il risultato è troncato a int */ x; //come sopra ma il risultato resta float m; // attenzione: la divisione tra int tronca //
  36. 36. Conversioni con il tipo bool • Il tipo bool ha valore true o false • I valori interi vengono convertiti a bool come segue – 0 viene convertito a false – ogni altro valore intero viene convertito a true • Vale anche la conversione inversa (promozione a int) bool b=false; int i; // inizializzazione i = b; // i vale 0 b=true; i = b; // i ora vale 1!
  37. 37. Conversioni con tipi un/signed • Ecco perché è meglio non mescolare unsigned u = 10; int i = -42; cout << i + i << endl; // prints -84 cout << u + i << endl; // if 32-bit ints, prints 4294967264 • Il valore di i (-42) viene convertito a unsigned prima dell’addizione unsigned u1 = 42, u2 = 10; cout << u1 - u2 << endl; // ok: result is 32 cout << u2 - u1 << endl; // ok: but the result is… ?
  38. 38. Quando avvengono le conversioni automatiche • Nelle espressioni, i valori di tipi aritmetici piccoli vengono solitamente promossi a int char c, int i; i=c+i; // da evitare • Nelle condizioni, tipi non bool sono convertiti a bool – while (33) equivale a while (true) ! • Nell’inizializzazione, il valore dell’inizializzatore è convertito al tipo della variabile inizializzata – int i = 3.14; // i inizializzato a 3 ! • Nelle espressioni aritmetiche, gli operando sono convertiti a un tipo comune • Nelle chiamate di funzione (che vedremo)
  39. 39. Altri esempi bool b = 42; // b is true int i = b; // i has value 1 i = 3.14; // i has value 3 double pi = i; // pi has value 3.0 // assuming 8-bit chars unsigned char c = -1; // c has value 255
  40. 40. Conversione (cast) esplicita • Quando una conversione utile non verrebbe eseguita, la si può richiedere esplicitamente • Es: divisione tra interi con risultato double x = (double) n / m; • ES: troncamento esplicito del risultato cout << (int) x / y; • C++11 introduce una sintassi più precisa
  41. 41. ATTENZIONE • Il cast (implicito o esplicito che sia) non modifica il tipo della variabile o delle variabili coinvolte, ma solo il tipo associato al valore dell'espressione • Le variabili in memoria continuano a essere del tipo dichiarato staticamente nella parte dichiarativa del programma • Il cambio del tipo della variabile può portare al cambio del valore dell’espressione dove la variabile è usata
  42. 42. Le espressioni • Espressione: applicazione di operatori a operandi – Ha un valore e un tipo – Condizione: espressione con tipo booleano • Cosa bisogna sapere sulle espressioni 1. Ordine di valutazione 2. Proprietà degli operandi (precedenza, associatività) 3. Tipo degli operatori e del risultato, conversioni
  43. 43. Espressioni base Le espressioni base si compongono di: • Variabili – Il tipo è noto in base alla dichiarazione, e NON cambia • Valori (detti anche costanti o literal) – Il tipo è deducibile da come sono “scritte” • • • • • • • 3 : int (il più piccolo tra int, long, long long in cui il valore ci sta) 03 : int in notazione ottale 0x3 : int in notazione esadecimale 3.0 : float 3.0L : long '3' : char "3" : stringa (sequenza di caratteri di lunghezza variabile)
  44. 44. Constanti di tipo stringa "Hello World!" // string literal •Ha un tipo composto che vedremo in seguito – Array di const char •Il compilatore appende al valore un carattere speciale "terminatore" ('0') •La dimensione reale del valore è 1 + la dimensione apparente (c'è anche il carattere "terminatore") •Attenzione: "a" ha tipo e dimensione diversi da 'a'
  45. 45. Espressioni e operatori • Operatori unari: sia applicano a un operando – -2 • Operatori binari: sia applicano a due operandi – a+b • Il valore di un'espressione dipende da precedenza e associatività degli operatori e può dipendere dall'ordine di valutazione delle sottoespressioni – Quanto vale : 5 + 10 * 20/2 ? • Nella valutazione intervengono anche le conversioni di tipo
  46. 46. Precedenza e associatività • • • • • Un'espressione con due o più operatori di dice composta La sua valutazione richiede di assegnare gli operandi agli operatori Si usano le regole di precedenza tra operatori diversi e le regole di associatività per operatori con la stessa precedenza – Precedenza: 3+4*5 vale 23, non 35 – Associatività: 20-15-3 vale 2, non 8 (associatività a sinistra) Le parentesi possono cambiare le regole – (3+4)*5 vale 35 – 20-(15-3) vale 8 Non solo operatori aritmetici: – – – – cin >> v1 >> v2; // read into v1 and then into v2 L'operatore >> è associativo a sinistra Il valore dell'espressione cin >> v1 è cin ! Equivale a (cin >> v1) >> v2;
  47. 47. Ordine di valutazione operandi • In generale l'ordine di valutazione di sotto-espressioni con la stessa priorità NON è definito – int i = f1() + f2(); // f1, f2 sono funzioni • Non si sa quale tra le funzioni f1() e f2() venga valutata per prima • Non si devono fare ipotesi indebite – int i = 0; – cout << i << " " << ++i << endl; // undefined – ++i espressione che incrementa i e "torna" il nuovo valore – Potrebbe stampare 1 1 oppure 0 1 o qualsiasi altra cosa • Ci sono 4 operatori per cui invece è stabilito l'ordine di valutazione delle sotto-espressioni – AND logico (&&) OR logico (||) operatore condizionale (? :), operatore virgola (,)
  48. 48. Operatori aritmetici • Precedenza e associatività (tutti associativi a sinistra) • PS: % indica il resto delle divisione tra due interi – Se m e n sono interi e n è diverso da 0, • (m/n)*n + m%n = m – Non si applica a tipi in virgola mobile precedenza
  49. 49. Operatori logici e relazionali • Sono usati per costruire condizioni, cioè espressioni con valore di tipo bool precedenza
  50. 50. La regola del cortocircuito • Gli operatori AND e OR in C e C++ hanno un ordine di valutazione prefissato (a differenza delle pure espressioni della logica) – Prima l’operando di sinistra POI quello di destra • Vale una regola detta del cortocircuito che evita di valutare inutilmente l’operando di destra – AND: se l’operando di sinistra vale false – OR: se l’operando di sinistra vale true • La regola del corto circuito ha applicazioni interessanti, per esempio quando si ispezionano sequenze di dati (lo vedremo in seguito)
  51. 51. L’operatore di assegnamento • Anche = è un operatore! • L’operando di sinistra deve essere una variabile (più precisamente un lvalue), quello di destra un’espressione (più precisamente un rvalue) • Modifica lo stato del programma: assegna il valore dell’operando di destra all’operando di sinistra – – – – i=3 è un’espressione, il cui valore è l’operando di sinistra, cioè i! i=3; è un’istruzione! Per via del ; L’operatore = è associativo a destra x=y=3 equivale a x=(y=3) • Si assegna il valore 3 a y, il risultato dell’espressione è y • Si effettua l’assegnamento x=y che copia il valore di y in x, anche x vale 3 • L’inizializzazione NON è un assegnamento (mai ribadito abbastanza)
  52. 52. Esempi int i = 0, j = 0, k = 0; // initializations, not // assignment 1024 = k; // error: literals are rvalues i + j = k; // error: arithmetic expressions are rvalues k = 0; // result: type int, value 0 k = 3.14159; // result: type int, value 3
  53. 53. ATTENZIONE • Possiamo usare assegnamenti come condizioni e viceversa? • Si, perché = è un operatore, proprio come == • Di solito però… succede quando si sta commettendo un errore...! – x = y == 3; – while ( 3 = x ) • Ma soprattutto... // Assegna a x il valore 0 o 1 e non modifica // Errore di sintassi (3 non è una variabile) – while(x = 3) ... È SEMPRE VERO!!! (per ogni valore precedente di x) – while (x = 0) ... È SEMPRE FALSO!!! (per ogni valore precedente di x) – while (x = y) ... equivale a scrivere • x = y; • while ( y != 0 ) ... • Ancora peggio... – while (! (x = 0)) ... NON TERMINA MAI !!!!
  54. 54. I costruttori di tipi • A partire dai tipi predefiniti si possono creare nuovi tipi, che aggiungono proprietà speciali ai tipi predefiniti – – – – const reference pointer array • A questi si aggiungono costruttori di tipi definiti interamente dall'utente – class – struct (eredità del C, poco usato in C++)
  55. 55. Il qualificatore const • Talora serve definire una variabile che non cambi valore • Per farlo si premette const alla dichiarazione – const int modelloauto = 159; // tipo const int – const float pigreco = 3.14159265; // tipo const float • Un tipo const è diverso dal corrispondente tipo base • Una variabile const – Si dichiara e inizializza obbligatoriamente – Non ammette assegnamento • • • • • int i = 42; const int ci = i; // ok: the value in i is copied into ci ci = 43; // error, no assignment const int k; // error: k is uninitialized const int j = ci; // ok: the value in ci is copied into j
  56. 56. Visibilità delle variabili const • const float pigreco = 3.14159265; • Il compilatore sostituisce pigreco con il valore associato • Il compilatore deve conoscere il valore dell'inizializzatore • Se il programma è diviso in più file, la variabile const viene (ri)definita in ciascun file • Alternativamente, la variabile const può essere definita in un solo file e dichiarata come esterna nei file che ne fanno uso
  57. 57. extern const • Per definire una variabile const una sola volta, si usa la keyword extern sia nella definizione che nelle dichiarazioni // file_1.cc definisce e inizializza una variabile const extern const float pigreco = 3.14159265; // file_1.h extern const float pigreco; // stessa const di file_1.cc • file_1.cc definisce e inizializza pigreco. Siccome la dichiarazione comprende un inizializzatore è una definizione. Però, siccome pigreco è const, si specifica extern per farla usare in altri file. • La dichiarazione in file_1.h è anch'essa extern. Significa che pigreco non è locale a tale file ma definita altrove • Altri file possono includere il file file_1.h e importare la definizione di pigreco
  58. 58. Definizione di macro: #define • Esiste anche un altro modo di definire un valore una volta per tutte – la direttiva #define • #define PIGRECO 3.141592 – #define è una direttiva al preprocessore (come #include) – Non è terminata dal punto e virgola • una direttiva al precompilatore non è un’istruzione C++ – Non causa allocazione di memoria • PIGRECO è una "costante simbolica" – Il simbolo PIGRECO viene sostituito nel codice con il valore 3.14 … prima che il programma sia compilato – Si dice che PIGRECO è una macro-definizione (o semplicemente una MACRO) – Per convenzione, le costanti definite tramite macro sono interamente maiuscole (es: TIPICA_COSTANTE)
  59. 59. Definizione di macro: #define • #define MIGLIO 1609.34 • #define YARDA 0.9144 • Si possono costruire MACRO a partire da altre MACRO, e una macro può anche usare uno o più parametri: – #define AREACERCHIO(X) (PIGRECO∗(X)∗(X)) – area = AREACERCHIO(4); – Diventa ⇒ area = (3.141592∗(4)∗(4)); – ma è un valore fisso !!
  60. 60. Altre direttive al precompilatore • Abbiamo già visto: #include <nome_libreria> – Serve a richiamare librerie – comanda al preprocessore di leggere anche da un altro file sorgente • Altra direttiva usata frequentemente: #undef VERO – Serve ad annullare la definizione di una MACRO – Da quel punto in poi la costante VERO non è più definita
  61. 61. Esempio di programma multifile /* File contenente funzioni di utilità sui cerchi * dichiarazione e definizione di una costante * riusabile : pigreco.cpp */ extern const float pigreco = 3.14159265; float area(float r){ return r*r*pigreco; } float perimeter(float r){ return 2*r*pigreco; }
  62. 62. File di intestazione della libreria /* * * * * File contenente solo le dichiarazioni delle funzioni di utilità sui cerchi e della costante riusabile: pigreco.h Usato dal compilatore per controllare la correttezza del programma */ extern const float pigreco; float area(float r); float perimeter(float r);
  63. 63. Programma principale #include <iostream> #include "pigreco.h" using namespace std; int main() { float radius; cout << "Insert the value of the radius: " << endl; cin >> radius; cout << "Value of pigreco: " << pigreco << endl; cout << "Perimeter of circle: " << perimeter(radius) << cout << "Area of the circle: " << area(radius) << endl; return 0; } endl;
  64. 64. I tipi definiti dall'utente • La ragione principale del successo di C++ è che consente di estendere il sistema dei tipi in modo assai potente • La novità introdotta dal C++ è che i tipi definiti dall'utente si possono usare (quasi) come quelli predefiniti
  65. 65. Requisiti • Si vuole costruire un programma che gestisca le vendite di libri • Ogni libro è caratterizzato da un codice ISBN • Il programma deve gestire per ogni libro il numero totale di copie vendute, il ricavo totale e medio • L'utente inserisce sequenzialmente i dati di vendita per i diversi libri, il programma aggrega i dati per ciascun codice ISBN e stampa il dato aggregato • Deve quindi essere possibile: – Inserire e stampare i dati di un libro – Sommare più dati di vendita relativi allo stesso libro – Stampare i dati di vendita aggregati relativi a un libro
  66. 66. Progettazione • Inizializza il totale vendite a 0 • Leggi dati 1° transazione e aggiorna il totale • Finché ci sono transazioni – Leggi un'altra transazione; – Se la transazione letta è dello stesso libro di prima • sommala al totale corrente; – Altrimenti • stampa il totale corrente; // è cambiato il libro • inizializza il totale corrente del nuovo libro coi dati della transazione letta; • Stampa il totale di vendita dell'ultimo libro (perché serve??)
  67. 67. Suddivisione del programma • Un file di libreria (Sales_item.h) conterrà la definizione del tipo che rappresenta il dato di vendita: Sales_item • Sales_item è un tipo classe, cioè un tipo definito dall'utente che comprende dati e operazioni relativi al dato di vendita • Il programma principale (Booksales.cpp) importa e usa Sales_item come se fosse un tipo predefinito – Sales_item item; // dichiara una var. di tipo Sales_item !
  68. 68. Un primo esempio di main() #include <iostream> #include "Sales_item.h" int main() { Sales_item book; // read ISBN, number of copies sold, and sales price std::cin >> book; // write ISBN, # of copies sold, total revenue, and average price std::cout << book << std::endl; return 0; } •book è trattata come una variabile di un tipo predefinito •Si applicano gli stessi operatori di I/O che a una variabile di tipo int •Gli operatori sono definiti nel tipo classe Sales_item
  69. 69. L'esempio completo int main() { Sales_item total; // variable to hold data for the next transaction // read the first transaction and ensure that there are data to process if (cin >> total) { Sales_item trans; // variable to hold the running sum // read and process the remaining transactions while (cin >> trans) { // if we're still processing the same book if (total.isbn() == trans.isbn()) total += trans; // update the running total else { // print results for the previous book cout << total << endl; total = trans; // total now refers to the next book } } cout << total << endl; // print the last transaction } else { // no input! warn the user cerr << "No data?!" << endl; return -1; // indicate failure } return 0; } if(cin >> x) while(cin >> x) La condizione è soddisfatta se l'acquisizione dell'input non ha dato errori Per terminare, basta premere CTRL-Z (carattere end of file)

×