Il main program Ogni programma in C per

  • Slides: 36
Download presentation
Il main program • Ogni programma in C++, per essere eseguibile, deve contenere una

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; }

I/O: lettura e scrittura • Non esiste nel C++ nativo. Si usa: iostream #include

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

Commenti • Esistono due tipi di commento in C++ – inline: const int Ntries;

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)

Tipi predefiniti in C++ • Sono definiti una serie di tipi numerici che permettono

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

Tipi predefiniti in C++ (2) Costanti carattere Esempi di costanti 123 0 x 123

Tipi predefiniti in C++ (2) Costanti carattere Esempi di costanti 123 0 x 123 l 123 u ‘A’ 3. 14 f ‘ 1’ ‘t’ 3. 1415 L 300 e-2. 03 e 2 interi costanti, decimale, ottale, esadecimale interi, long, unsigned caratteri, tab float, double, long double, notazione esponenziale stringa costante boolean 30 e-1 “Nome” true false ‘a’ ‘\’ ‘b’ ‘r’ ‘”’ ‘f’ ‘t’ ‘n’ ‘’ ‘’’ ‘v’ ‘101’ ‘x 041’ 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 (‘’) ‘n’ ‘o’ ‘m’ ‘e’ ‘’ stampa: una “stringa” un alla fine della linea per continuare la stringa

Tipi predefiniti in C++ (3) OS OS OS 16 bit 32 bit 64 bit

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 [1] Può essere unsigned

Identificatori • Un identificatore è composto da uno o più caratteri • Il primo

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 2 A; // 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!

Keywords • Alcuni identificatori sono esplicitamente riservati al sistema (hanno un preciso significato in

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_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_cast struct switch template this throw true try typedef typeid typename union unsigned using virtual void volatile wchar_t while

const • La keyword const viene utilizzata per dichiarare un oggetto costante Esempi di

const • La keyword const viene utilizzata per dichiarare un oggetto costante Esempi di 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)

Dichiarazione • Le dichiarazioni associano un significato ad un identificatore • in C++ ogni

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 r 1, double r 2); // 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 r 1, double r 2) { return (r 1>r 2) ? r 1: r 2; } // definizione // dichiarazione // definizione di max

typedef • L’istruzione typedef viene utilizzata per creare un alias per tipi esistenti typedef

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

Enumeratori • In C++ sono supportati tipi definiti dall’utente enum Color { red, green,

Enumeratori • In C++ sono supportati tipi definiti dall’utente enum Color { red, green, blue }; Color screen. Color = blue; Color windor. Color = red; int n = blue; // valido Color c = 1; // errore enum Seme { cuori, picche, quadri, fiori };

Scope • Le variabili possono essere dichiarate e definite quasi ovunque in un programma

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!

Scope (2) • Attenzione! La stessa variabile può essere ridichiarata (con visibilità diversa). Questo

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

Operatori Espressioni Aritmetiche Auto-incremento e decremento k k = = ++j; j++; --j; j--;

Operatori Espressioni Aritmetiche Auto-incremento e decremento k k = = ++j; j++; --j; j--; -i a*b +w a/b a+b a-b i%2 a=3; Espressione j=j+1; k=j; j=j+1; j=j-1; k=j; j=j-1; Commento piu` e meno unari moltiplicazione, divisione, modulo addizione e sottrazione binarie assegnazione Operatori relazionali < > <= >= bit-wise significato == != ~i; Complemento bit a bit ! i&j; AND bit a bit && i|j OR bit a bit || i^j XOR bit a bit i<<n shift a sinistra di n pos. i>>n shift a destra di n pos. minore di maggiore di minore o uguale maggiore o uguale diverso Negazione unaria and logico or logico Fortran. LT. . GT. . LE. . GE. . EQ. . NE. . NOT. . AND. . OR.

Espressioni di assegnazione • Le espressioni di assegnazione sono valutate da destra a sinistra

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 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;

Statements Statement C++ vuoto espressione composto ; j=j+k; {. . } goto if goto

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

Statements (2) Statement switch C++ dichiarazione switch (s) { case 1: ++i; case 2:

Statements (2) Statement switch C++ dichiarazione switch (s) { case 1: ++i; case 2: --i; default: ++j; }; int i=7; 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

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

if • Attenzione all’uso di = e == if (i=1) {. . } //

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;

while e do-while • La forma generale di un while è : while (condizione)

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

break e continue • break e continue sono utilizzati nei loop per saltare alla

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

switch • Lo switch è uno statement condizionale che generalizza lo if-else switch (condizione)

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<<“ case 1: case 3: cout<<“ case 2: case 4: cout<<“ default: cout<<“ } n e` case n e` nullo”<<endl; break; 5: case 7: case 9: dispari”<<endl; break; 6: case 8: case 10: pari”<<endl; break; n non e` compreso tra 0 e 10”<<endl;

switch (2) • Non si puo` dichiarare una variabile in uno dei case switch

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

L’operatore ? • L’operatore ? e` l’unico esempio di operatore ternario in C++ expr

L’operatore ? • L’operatore ? e` l’unico esempio di operatore ternario in C++ expr 1 ? expr 2 : expr 3; – Equivale a: if(expr 1) expr 2; else expr 3; – Esempio: double max(double a, double b) { double max = (a>b) ? a : b; return max; }

Funzioni matematiche • In C++ non esistono funzioni predefinite #include <iostream> #include <cmath> using

Funzioni matematiche • In C++ non esistono funzioni predefinite #include <iostream> #include <cmath> using namespace std; int main() { double r, theta, phi; cin >> 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 <<

Array • Sono supportati gli array di dimensione fissa int main() { int x[10];

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’, ‘’ }; 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.

Esempio con gli arrays • Moltiplicazione fra matrici: int main() { const int DIM=3;

Esempio con gli arrays • Moltiplicazione fra matrici: int main() { const int DIM=3; float m[DIM], m 1[DIM], m 2[DIM]; // Assumiamo che m 1 ed m 2 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 += m 1[i][k] * m 2[k][j]; m[i][j] = sum; } } return 0; }

Puntatori • Riferimento ad una locazione di memoria #include <iostream> using namespace std; ptr

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 0 x 7 b 03 a 928 } indirizzo di memoria

Puntatori • Puntatore nullo #include <iostream> ptr j 12 using namespace std; int main()

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)

Puntatori e array • In C gli array sono trattati come puntatori X[0] 1.

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+1) = *(ptr+3) = } = x; 1. 5; // x[0] = 1. 5 2. 5; // x[1] = 2. 5 3. 5; // x[3] = 3. 5 X[2] 0. 0 X[3] 3. 5 X+3 X[4] 0. 0

Puntatori: allocazione dinamica • Riferimento ad una locazione di memoria #include <iostream> ptr using

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

Puntatori: allocazione dinamica • Riferimento a più locazioni di memoria #include <iostream> using namespace

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

new e delete • Gli operatori new and delete vengono utilizzati per allocazione/deallocazione di

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 caratteri 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

new e delete (2) • L’operatore delete è usato per restituire una certa area

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 ptr; delete p[i]; delete [] p; commenti distrugge un puntatore ad un oggetto distrugge l’oggetto p[i] distrugge ogni oggetto di tipo p

new e delete (3) • Attenzione – la dimensione dello heap non e` infinita

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