...

Lezione sui tipi di base in C++ - ICAR-CNR

by user

on
Category: Documents
14

views

Report

Comments

Transcript

Lezione sui tipi di base in C++ - ICAR-CNR
Il main program
• Ogni programma in C++, per essere
eseguibile, deve contenere una funzione
main() da cui l’esecuzione comincerà
• main() deve avere un tipo (decidere quale è
compito del programmatore). Regola generale
è che main() ritorni un intero, a significare il
return code dell’applicazione
int main()
{
// il piu` semplice programma in C++
return 0;
}
1
I/O: lettura e scrittura
• Non esiste nel C++ nativo. Si usa: iostream
#include <iostream>
– Gli operatori << e >> sono usati per definire la
direzione del flusso
– cin, cout e cerr rappresentano lo standard input,
output e error del programma
#include <iostream>
using namespace std;
int main()
{
cout << “Hello, world !” << endl;
return 0;
}
direttiva al
preprocessore
end of line
2
Commenti
• Esistono due tipi di commento in C++
– inline:
const int Ntries; // questo e` un commento inline
// il resto della linea e’ trattato come un commento
– multiline (come in C):
const int Ntries;
/* questo e` un commento multiline:
tutto viene trattato come un commento
fino a quando il commento stesso non
viene chiuso con uno */
– I due tipi possono essere usati indifferentemente, ma
si raccomanda di usare l’inline (più semplice e meno
ambiguo)
3
Tipi predefiniti in C++
• Sono definiti una serie di tipi numerici che
permettono di rappresentare numeri interi, reali e
caratteri
int
long
float
double
long double
unsigned int
unsigned double
char
bool
intero in singola precisione
intero in doppia precisione
reale in singola precisione
reale in doppia precisione
reale in precisione estesa
intero senza segno
reale senza segno in doppia precisione
carattere singolo
variabili logiche
– char (un solo byte) viene normalmente usato per
rappresentare interi inferiori a 256
– stringhe e numeri complessi sono implementati come
tipi derivati
4
Tipi predefiniti in C++ (2)
Costanti carattere
Esempi di costanti
123
123
0x123
123l
123u
‘A’
3.14f
‘1’
‘\t’
3.1415 3.1415L
300e-2 .03e2
interi costanti,
decimale, ottale,
esadecimale
interi, long,
unsigned
caratteri, tab
float, double,
long double
double, notazione
esponenziale
stringa costante
boolean
30e-1
“Nome”
true
false
‘\a’
‘\\’
‘\b’
‘\r’
‘\”’
‘\f’
‘\t’
‘\n’
‘\0’
‘\’’
‘\v’
‘\101’
‘\x041’
alert
backslash
backspace
carriage return
double quote
form feed
tab
newline
carattere nullo
single quote
vertical tab
101 ottale, ‘A’
esadecimale, ‘A’
Stringhe costanti
“”
“nome”
“una \”stringa\””
“una stringa \
su piu` linee”
stringa nulla (‘\0’)
‘n’ ‘o’ ‘m’ ‘e’ ‘\0’
stampa: una “stringa”
un \ alla fine della linea
per continuare la stringa
5
Tipi predefiniti in C++ (3)
OS
OS
OS
16 bit 32 bit 64 bit
char[1]
8
8
8
int[1]
16
32
32
bool
16
32
32
short[1]
16
16
16
long[1]
32
32
64
float
32
32
32
double
64
64
64
long double
64
128
128
[1] Può essere unsigned
6
Identificatori
• Un identificatore è composto da uno o più caratteri
• Il primo carattere deve essere una lettera o un
underscore. Caratteri successivi possono essere
lettere, numeri o underscore const int Ntries;
double _attempts;
double 2A; // errore!
• Non c’ è un limite in lunghezza, anche se alcuni
sistemi si limitano a considerare i primi 31 caratteri
• Gli identificatori che iniziano con un doppio
underscore o con un underscore e una lettera
maiuscola sono riservati ad usi di sistema
• C++ e` case sensitive!
7
Keywords
• Alcuni identificatori sono esplicitamente riservati al
sistema (hanno un preciso significato in C++) e non
possono essere usati
asm
auto
bool
break
case
catch
char
class
const
const_cast
continue
default
delete
do
double
dynamic_cast
else
enum
explicit
extern
false
float
for
friend
goto
if
inline
int
long
mutable
namespace
new
keyword
operator
private
protected
public
register
reinterpret_cast
return
short
signed
sizeof
static
static_cast
struct
switch
template
this
throw
true
try
typedef
typeid
typename
union
unsigned
using
virtual
void
volatile
wchar_t
while
8
const
• La keyword const viene utilizzata per
dichiarare un oggetto costante
Esempi di const
const int N=100;
double w[N];
const int vect[5]=
{10,20,30,40,50};
N non puo` essere cambiato
N usato come per dimensionare
un vettore
le componenti di vect non
possono essere cambiate
• In C le costanti vengono normalmente dichiarate
usando il preprocessore #define N 100
– in questo caso N e` una costante senza tipo ed il
preprocessore sostituisce N ovunque lo trovi nel
programma, senza rispettare le regole di scope (da
evitare)
9
Dichiarazione
• Le dichiarazioni associano un significato ad
un identificatore
• in C++ ogni cosa deve essere dichiarata per
poter essere usata
const int i;
double max(double r1,double r2);
// la variabile i
// la funzione max
• Una dichiarazione è spesso anche una
definizione. Per variabili semplici questo
consiste nell’associare un valore alla variabile
al momento della dichiarazione
const double pi=3.1415926;
double max(double r1, double r2) {
return (r1>r2) ? r1: r2;
}
// definizione
// dichiarazione
// definizione di max
10
typedef
• L’istruzione typedef viene utilizzata per
creare un alias per tipi esistenti
typedef int INTEGER;
typedef int BOOLEAN;
typedef void (*ptr_f)();
//
//
//
//
//
per i nostalgici del fortran
usato prima che bool venisse
implementato
ptr_f e` un puntatore ad una
procedura (subroutine)
• typedef NON può essere usato per
implementare nuovi tipi, ma solo per definire
un alias
typedef mela frutto;
// compila soltanto se mela
// e` gia` stata definita
11
Enumeratori
• In C++ sono supportati tipi definiti dall’utente
enum Color
{
red, green, blue
};
Color screenColor = blue;
Color windorColor = red;
int
n = blue; // valido
Color c = 1;
// errore
enum Seme
{
cuori, picche, quadri, fiori
};
12
Scope
• Le variabili possono essere dichiarate e definite
quasi ovunque in un programma in C++
• la visibilità (scope) di una variabile dipende da
dove la variabile è stata dichiarata
int func()
{
…
const int n=50;
for (int i=0;i<100;i++)
{
double r;
...
}
cout<<“n “<< n <<endl;
cout<<“i “<< i <<endl;
cout<<“r “<< r <<endl;
…
}
// function scope
// i e` locale
// r e` locale
// OK
// errore! Ma...
// errore!
13
Scope (2)
• Attenzione! La stessa variabile può essere ridichiarata (con visibilità diversa). Questo è da
evitare (se possibile) per non rendere il
programma oscuro e a rischio di errore!
int i;
int func()
{
int i=50;
// file (global) scope
// function scope, nasconde
// la i a file scope
for (int i=0;i<100;i++)
// block scope. Nasconde
// la i a function scope
{
int i;
// questo e` un errore...
...
}
cout<<“i “<< i <<“ “<< ::i <<endl;
...
}
Scope resolution operator
14
Operatori
Espressioni Aritmetiche
Auto-incremento
e decremento
k
k
k
k
=
=
=
=
++j;
j++;
--j;
j--;
+w
a/b
a+b
a-b
i%2
a=3;
Espressione
j=j+1; k=j;
k=j; j=j+1;
j=j-1; k=j;
k=j; j=j-1;
bit-wise
~i;
i&j;
i|j
i^j
i<<n
i>>n
-i
a*b
significato
Commento
piu` e meno unari
moltiplicazione,
divisione, modulo
addizione e
sottrazione binarie
assegnazione
Operatori relazionali
<
>
<=
>=
==
!=
!
&&
||
Complemento bit a bit
AND bit a bit
OR bit a bit
XOR bit a bit
shift a sinistra di n pos.
shift a destra di n pos.
minore di
maggiore di
minore o uguale
maggiore o uguale
uguale
diverso
Negazione unaria
and logico
or logico
Fortran
.LT.
.GT.
.LE.
.GE.
.EQ.
.NE.
.NOT.
.AND.
.OR.
15
Espressioni di assegnazione
• Le espressioni di assegnazione sono valutate da
destra a sinistra
a = j++;
j viene incrementato ed il risultato assegnato ad a
• Le assegnazioni multiple sono permesse
a = b = c = d = 100;
• alcuni operatori di assegnazione combinano
assegnazione ed altri operatori
a *= b;
a -= b;
// equivale ad
// equivale ad
a = a*b;
a = a-b;
• Assegnazioni possono essere fatte all’interno di
espressioni aritmetiche
a = b + ( c = 3 );
// equivale a c=3; a=b+c;
16
Statements
Statement
C++
vuoto
espressione
composto
;
j=j+k;
{ . . . . }
goto
if
goto label;
if (p==0)
cerr<<“error”;
if (x==y)
cout<<“the same”;
else
cout<<“different”;
for (j=0;j<n;j++)
a[j]=0;
while (i != j)
i++;
do
y=y-1;
while (y>0);
break;
continue;
if-else
for
while
do-while
break
continue
commenti
usato in funzioni, if..
Costituisce un blocco
da non usarsi
un solo branch
due branch
le dichiarazioni sono
permesse
0 o piu` iterazioni
1 o piu` iterazioni
esce dal blocco
prossima iterazione
17
Statements (2)
Statement
switch
C++
dichiarazione
switch (s) {
case 1:
++i;
case 2:
--i;
default:
++j;
};
int i=7;
try
try {. . . .}
label
error:
cerr<<“Error!”;
return x*x*x;
return
commenti
si deve usare break per
evitare di cadere nei
casi successivi e
aggiungere un caso di
default alla fine della
lista
in un blocco, file o
namespace
usato per trattare le
eccezioni
usato con goto
valore di ritorno di
una funzione
18
Statement composti
• Uno statement composto in è costituito da una
serie di statement contenuti fra parentesi graffe
• Usato normalmente per raggruppare istruzioni in
un blocco (if, for, while, do-while, etc.)
• Il corpo di una funzione è sempre uno statement
composto
• La dichiarazione di una variabile può avvenire
ovunque all’interno di un blocco, in questo caso lo
scope della variabile sarà il blocco stesso
• Ovunque si possa usare uno statement singolo si
può definire un blocco
19
if
• Attenzione all’uso di = e ==
if (i=1)
{. . . .}
// questo e` sempre vero!!!
• Nel dubbio, usare sempre un blocco…
if (i != 0)
a++;
a/=i;
// possibile divisione per 0
// mancano delle {}?
• Attenzione agli else!
if (i == 0)
if (a<0)
{
// possibile divisione per 0
cerr<<“a e` negativo!”;
}
else
b=a/i;
20
while e do-while
• La forma generale di un while è :
while (condizione)
statement;
• Lo statement verrà eseguito fino a quando la
condizione verrà verificata (true). A seconda del
volore della condizione, lo statement verrà
eseguito zero o più volte
• la sintassi di un do-while è invece:
do
statement;
while (condizione);
• Lo statement verrà quindi eseguito almeno una
volta
21
break e continue
• break e continue sono utilizzati nei loop per
saltare alla fine del loop o fuori dal loop stesso
int i,n=0;
int a[100];
cin>>i;
// leggo il valore di i
while (1)
// loop infinito
{
if (i<0) break;
if (n>=100) continue;
a[n]=i;
n++;
// continue salta qui
}
// break salta qui
• break e continue possono solamente essere
utilizzati nel corpo di un for, while o dowhile. break e` anche usato negli switch
22
switch
• Lo switch è uno statement condizionale che
generalizza lo if-else
switch (condizione)
(statement);
• lo statement è generalmente composito e
consiste di diversi case e, opzionalmente, di
un default
switch (n) {
case 0:
cout<<“ n e` nullo”<<endl; break;
case 1: case 3: case 5: case 7: case 9:
cout<<“ n e` dispari”<<endl; break;
case 2: case 4: case 6: case 8: case 10:
cout<<“ n e` pari”<<endl; break;
default:
cout<<“ n non e` compreso tra 0 e 10”<<endl;
}
23
switch (2)
• Non si puo` dichiarare una variabile in uno dei case
switch (k)
case 0:
int
. .
case 1:
. .
}
{
j=0;
.
// Illegale! Errore!
.
• … ma si puo` creare una variabile locale definendo
uno statement composto...
switch (k)
case 0:
{
int
. .
}
case 1:
. .
}
{
j=0;
.
// OK, questo compila
.
24
L’operatore ?
• L’operatore ? e` l’unico esempio di operatore
ternario in C++
expr1 ? expr2 : expr3;
– Equivale a:
if(expr1)
expr2;
else
expr3;
– Esempio:
double max(double a, double b)
{
double max = (a>b) ? a : b;
return max;
}
25
Funzioni matematiche
• In C++ non esistono funzioni predefinite
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double r, theta, phi;
cin >>
double
double
double
r
x
y
z
cmath.h definisce sin, cos, ...
>> theta >> phi ;
= r * sin( theta ) * sin( phi );
= r * sin( theta ) * cos( phi );
= r * cos( theta );
return 0;
}
• Potenze: pow(b,exp)
**endl;
)
cout << x << (non
“, “ <<siy può
<< “, usare
“ << z <<
26
Array
• Sono supportati gli array di dimensione fissa
int main()
{
int x[10];
for ( int i = 0; i < 10, i++ )
x[i] = 0;
double m[5][5];
for ( int i = 0; i < 5; i++ )
for ( int j = 0; j < 5; j++ )
m[i][j] = i * j;
return 0;
}
• Inizializzazione:
int x[] = { 1, 2, 3, 4 };
char[] t =
{ ‘C’, ‘i’, ‘a’, ‘o’, ‘\0’ };
char[] s = “Ciao”;
int m[2][3] =
{ {11, 12, 13}, {21, 22, 23} };
• L’indice va da 0 a n-1. Usare un indice
maggiore di n-1 può causare un crash.
27
Esempio con gli arrays
• Moltiplicazione fra matrici:
int main() {
const int DIM=3;
float m[DIM][DIM], m1[DIM][DIM], m2[DIM][DIM];
// Assumiamo che m1 ed m2 vengano riempiti qui...
// Moltiplicazione:
for (int i=0; i<DIM; i++) {
for (int j=0; j<DIM; j++) {
float sum=0;
for (int k=0; k<DIM; k++)
sum += m1[i][k] * m2[k][j];
m[i][j] = sum;
}
}
return 0;
}
28
Puntatori
• Riferimento ad una locazione di memoria
#include <iostream>
using namespace std;
ptr
j
24
12
int main()
{
int *ptr = &j;
int j = 12;
cout << *ptr << endl;
j = 24;
cout << *ptr << endl;
cout << ptr << endl;
return 0;
12
24
0x7b03a928
}
indirizzo di memoria
29
Puntatori
• Puntatore nullo
#include <iostream>
ptr
j
12
using namespace std;
int main()
{
int j = 12;
int *ptr = 0;
cout << *ptr << endl; // crash !
return 0;
}
Segmentation violation (core dumped)
30
Puntatori e array
• In C gli array sono trattati come puntatori
X[0]
1.5
X[1]
2.5
x
X+1
int main()
{
float x[5];
int j;
for (j = 0; j < 5; j++)
x[j] = 0;
float *ptr
*ptr
=
*(ptr+1) =
*(ptr+3) =
X[2]
0.0
X[3]
3.5
X[4]
0.0
X+3
= x;
1.5; // x[0] = 1.5
2.5; // x[1] = 2.5
3.5; // x[3] = 3.5
}
31
Puntatori: allocazione dinamica
• Riferimento ad una locazione di memoria
#include <iostream>
ptr
using namespace std;
12
int main()
{
int *ptr = new int;
*ptr = 12;
cout << *ptr << endl;
delete ptr;
return 0;
• Attenzione:
– Non usare delete}fa accumulare locazioni di
memoria inutilizzate (memory leak)
– Utilizzare puntatori prima del new o dopo il
delete causa il crash del programma
32
Puntatori: allocazione dinamica
• Riferimento a più locazioni di memoria
#include <iostream>
using namespace std;
int main()
{
int *ptr = new int[3];
ptr[0] = 10;
ptr[1] = 11;
ptr[2] = 12
delete [] ptr;
return 0;
}
ptr
10
11
12
33
new e delete
• Gli operatori new and delete vengono utilizzati
per allocazione/deallocazione di memoria dinamica
– la memoria dinamica (heap), è un’area di memoria libera
provvista dal sistema per quegli oggetti la cui durata di
vita è sotto il controllo del programmatore
operatore new
int *i=new int;
char *c=new char[100];
int *i=new int(99);
char *c=new char(‘c’);
int *j=new int[n][4];
commenti
alloca un
alloca un
caratteri
alloca un
alloca un
alloca un
intero, returna il puntatore
array (stringa) di 100
intero e lo inizializza a 99
carattere inizializzato a c
array di puntatori ad intero
• new riserva la quantità necessaria di memoria
richiesta e ritorna l’indirizzo di quest’area
34
new e delete (2)
• L’operatore delete è usato per restituire una
certa area di memoria (allocata con new) allo heap
• Ogni oggetto allocato con new deve essere
distrutto con delete se non viene piu` utilizzato,
altrimenti l’area di memoria che esso occupata
non potra` piu` essere ri-allocata (memory leak)
• L’argomento di delete è tipicamente un
puntatore inizializzato preventivamente con new
operatore delete
delete ptr;
delete p[i];
delete [] p;
commenti
distrugge un puntatore ad un oggetto
distrugge l’oggetto p[i]
distrugge ogni oggetto di tipo p
35
new e delete (3)
• Attenzione
– la dimensione dello heap non e` infinita
– l’allocazione con new può fallire, nel qual caso new
restituisce un puntatore nullo o suscita un’eccezione.
Nel caso di allocazione di memoria importante
bisogna verificare che l’operazione abbia avuto
successo prima di usare il puntatore
– ogni oggetto creato con new deve essere distrutto
con delete, ogni oggetto creato con new [] deve
essere distrutto con delete [] , queste forme
NON sono intercambiabili
36
Fly UP