uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Iteratori e puntatori C++
Fondamenti di informatica
Michele Tomaiuolo
tomamic@ce.unipr.it
http://www.ce.unipr.it/people/tomamic
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Iteratore
Modo uniforme per scorrere le collezioni di dati
Astrazione che nasconde dettagli implementativi
Ogni tipo di collezione (vector, map... anche string) ha il suo tipo di iteratore
Ma stessa terminologia, sintassi e semantica
Metodo begin()
Restituisce iteratore sul primo elemento
Metodo end()
Iteratore oltre l'ultimo elemento della collezione
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Operazioni su iteratori
Operatore di incremento ++
Avanzare l’iteratore all’elemento successivo
Operatori di confronto == e !=
Verificare se due iteratori puntano allo stesso elemento
Operatore di dereferenziazione *
Accedere all’elemento puntato dall’iteratore
Alcuni iteratori supportano anche l'operatore di
decremento -- e quello per accesso casuale []
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
vector<int> values;
int val; cin >> val;
while (val != 0) {
values.push_back(val);
cin >> val;
}
// print out content:
cout << "values are: ";
vector<int>::iterator i;
for (i = values.begin(); i != values.end(); ++i) { cout << " " << *i;
}
Scorrere un vector
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
map<string, int> counts;
string word; cin >> word;
while (word != "end") { ++counts[word];
cin >> word;
}
map<string, int>::iterator i;
for (i = counts.begin(); i != counts.end(); ++i) { cout << "Word: " << (*i).first;
cout << " Count: " << (*i).second << endl;
}
Scorrere una map
Ogni elemento di una map è una coppia chiave / valore
(first, second) Ogni elemento di una map è una coppia chiave / valore
(first, second)
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
vector<string> lines;
string line; getline(cin, line);
while (line != "") {
lines.push_back(line);
string::iterator i; // will go backwards
for (i = line.rbegin(); i != line.rend(); ++i) { cout << (*i) << endl; // each char on a line }
getline(cin, line);
}
vector<string>::iterator j; // will go backwards for (j = lines.rbegin(); j != lines.rend(); ++j) { cout << (*j) << endl; // each string on a line }
Reverse iterator
Molte collezioni hanno anche iteratori
che procedono all'indietro Molte collezioni hanno anche iteratori
che procedono all'indietro
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Algoritmi
Le librerie STL contengono algoritmi generici
sort, reverse, copy, find, max, min...
Operano su iteratori
// example of a comparison function
bool compare(int i, int j) { return (i*i < j*j); } // … [in some other function]
// sort(someVector.begin(), someVector.end());
sort(someVector.begin(), someVector.end(), compare);
Parametri i e j:
stesso tipo degli elementi di someVector Parametri i e j:
stesso tipo degli elementi di someVector
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
ElementType arrayName[SIZE]
Si specifica il tipo e il numero degli elementi
Simile a vector, ma... dimensione costante!
Dim. fissata a tempo di compilazione e immutabile Elementi in locazioni
contigue di memoria
Indice: da 0 a SIZE – 1
Nessun controllo automatico!
Né in compilazione,
Array
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
const int MAX_SIZE = 100;
int size, i, values[MAX_SIZE];
cout << "Size (max 100):"; cin >> size;
if (size > MAX_SIZE) { cout << "Too large"; } } else {
// read values
for (i = 0; i < size; ++i) {
cout << "Insert value: "; cin >> values[i];
}
// write values, in reverse order for (i = size - 1; i >= 0; --i) { cout << values[i];
} }
Inversione array
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
const int ROWS = 2; const int COLS = 3;
int x, y, sum; int matrix[ROWS][COLS];
for (y = 0; y < ROWS; ++y) { for (x = 0; x < COLS; ++x) {
cout << "Elem #" << y << ',' << x << ': ';
cin >> matrix[y][x];
} }
for (y = 0; y < ROWS; ++y) { sum = 0;
for (x = 0; x < COLS; ++x) { sum += matrix[y][x];
}
cout << "Row #" << y << " sums to " << sum;
Array multidimensionali
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
const int ROWS = 2; const int COLS = 3;
int x, y, sum; int matrix[ROWS * COLS];
for (y = 0; y < ROWS; ++y) { for (x = 0; x < COLS; ++x) {
cout << "Elem #" << y << ',' << x << ': ';
cin >> matrix[y * COLS + x];
} }
for (y = 0; y < ROWS; ++y) { sum = 0;
for (x = 0; x < COLS; ++x) { sum += matrix[y * COLS + x];
}
cout << "Row #" << y << " sums to " << sum;
Array pseudo-multidimensionale
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Ogni dato presente in memoria ha un indirizzo Variabile puntatore per memorizzarlo
Specificare tipo del dato a cui punta int *p;
Operatore & per indirizzo di un dato
p = &i;
Se non punta a nessun dato:
p = NULL;
Puntatore
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Dereferenziazione
Operatore * per accesso al dato puntato
Dato che risiede all'indirizzo di memoria contenuto nel puntatore
float pi = 3.14f;
float* gg;
gg = π
*gg = *gg + 1; // pi = 4.14
cout << *gg; // writes 4.14
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Sommare ad un puntatore p un intero i
Rispetto all'indirizzo contenuto in p, si avanza di i posizioni (offset)
Spostamento in byte = i * dim. tipo di dato puntato Array molto simile a un puntatore (ma costante!)
Puntatori e array
int a[100]; int *b;
b=a;
cout << *(b+4); // same as a[4] … or b[4]
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
int m, n;
int* max;
cout << "Insert two numbers: ";
cin >> m, n;
if (m > n) { max = &m;
} else { max = &n;
}
cout << "Max: " << *max;
Max tra due numeri
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Comprensione dei puntatori
Dichiarazioni complesse, ricordare le seguenti regole:
Operatore array [] e l'op. di funzione () hanno precedenza maggiore rispetto all'operatore *
Gli operatori [] e () vengono raggruppati da sinistra, mentre l'operatore * da destra
int *(*pap)[];
int *(*pfp)();
int (*fpa())[];
int (*fpf())();
int *(**ppf)();
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
char *x[] viene decifrata nel modo seguente:
x[] è un array
*x[] è un array di puntatori
char *x[] è un array di puntatori a char
int (*x[])() viene decifrata nel modo seguente:
x[] è un array
(*x[]) è un array di puntatori
(*x[])() è un array di puntatori a funzioni
int (*x[])() è un array di puntatori a funzioni che restituiscono un intero
Analisi di una dichiarazione
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Allocazione dinamica
Un programma può richiedere memoria esplicitamente a tempo di esecuzione
Memoria necessaria nota solo a runtime
Stessa memoria riutilizzata per scopi diversi
La memoria allocata deve essere rilasciata
Disponibile per successive allocazioni dinamiche Rilasciata comunque alla terminazione
Meccanismo di funzionamento interno sfruttato da
vector e altre collezioni STL
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
New e delete
Heap: zona di memoria destinata all’allocazione dinamica
Memoria allocata con operatore new Rilasciata con operatore delete
int *i = new int;
int lenght; cin >> length;
char *buffer = new char[length];
// …
delete[] buffer;
delete i;
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
int length, i;
cout << "Insert # of elements: ";
cin >> length;
int *values = new int[length];
for (i = 0; i < length; ++i) { cout << "Insert a value: ";
cin >> values[i];
}
for (i = length - 1; i >= 0; --i) { cout << values[i];
}
Inversione array in heap
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
// C++ (!=Java): “new” cannot allocate a matrix!
int rows=3, cols=3, size=rows*cols, y=1, x=2, i;
int *matrix1 = new int[size];
// …
matrix1[y * cols + x] = 5;
// …
delete[] matrix1;
int **matrix2 = new int*[rows];
for (i=0; i<rows; ++i) matrix2[i]=new int[cols];
// …
matrix2[y][x] = 5;
// …
for (i=rows-1; i>=0; --i) delete[] matrix2[i];
delete[] matrix2;
Matrice in heap
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8 matrix2
matrix1
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Memory leak
Purtroppo il C++ non ha la garbage collection Leak, se memoria non rilasciata dopo l'uso
Ad ogni new deve corrispondere un delete Indirizzo perso, senza richiamo delete
int *p;
p = new int[1000];
// ...
p = new int[1000]; // ERROR! Memory leak
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Dangling pointer
Riferimento a memoria già rilasciata
delete, ma esistenza di altri riferimenti a quell'area di memoria
Riferimento a variabili locali, fuori dal loro contesto (rilasciate automaticamente)
char *res;
if (a < b) {
char tmp[50] = "Local to the block!";
res = tmp; // ERROR! Dangling pointer
}
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Stringa C
In C non esisteva il dato di tipo stringa
Si usavano gli array di caratteri
char name[30]; // max 29 chars Fine stringa: codice 0 ('\0')
Assegnamento da literal
char name[10] = "Luca";
'\0' inserito automaticamente
Conversione da stringa C++: text.c_str();
L u 9c a \0 ? ? ? ? ?
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Lettura cstring da tastiera
Solo una parola, fino a spazio
cin.width(30); cin >> name;
Intera riga
cin.getline(name, 30);
// vs.: getline(cin, realString);
Parametro opzionale per carattere delimitatore, (anche per stringhe C++; default '\n')
Specificare lunghezza max (incluso '\0')
In modo da non “sporcare” la memoria
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Conteggio cifre in cstring
#include <cstring>
int main() {
const int MAX_SIZE = 128;
char text[MAX_SIZE];
int digits = 0;
cout << "Insert a string: ";
cin.getline(text, MAX_SIZE);
for (int i = 0; text[i] != '\0'; ++i) { if (text[i] >= '0' && text[i] <= '9') { ++digits;
} }
cout << "The # of digits is " << digits;
return 0;
}
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Manipolazione cstring
Lunghezza di s, escluso '\0'
strlen(s);
Copia stringa s2 in s1 (max n caratteri)
strncpy(s1, s2, n);
Concatena s2 alla fine di s1
strncat(s1, s2, n);
Confronta s1 con s2
strncmp(s1, s2, n);
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Riga di comando
La funzione main può ricevere argomenti
argc: numero di parametri da riga di comando argv: parametri come array di char* ( cstring)
argv[0] è il nome del programma
int main(int argc, char *argv[]) { for (int i = 0; i < argc; ++i) { cout << argv[i] << endl;
}
}
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
string line;
if (argc == 4) {
ifstream in(argv[1]);
ofstream out(argv[2]);
int lines = 0; istringstream(argv[3]) >> lines;
for (int i=0; i<lines && in.good(); ++i) { getline(in, line);
if (in.good()) {
out << line << endl;
} }
in.close();
out.close();
}
Copia prime righe
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
ofstream file(argv[1], ios::app);
string line;
while (getline(cin, line)) { file << line << endl;
}
file.close();
Aggiunta riga
Altri modi di apertura file sono definiti in ios
I flag sono combinabili tramite | (bitwise or) Altri modi di apertura file sono definiti in ios
I flag sono combinabili tramite | (bitwise or)
Modo “append”, Aggiunta in fondo
Modo “append”, Aggiunta in fondo
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
File di log
Di solito i flussi clog e cerr coincidono con il flusso cout
Però è possibile redirigerli su file:
ofstream ofs("logfile.log");
clog.rdbuf(ofs.rdbuf());
In questo modo si può tenere traccia dello stato di esecuzione dell'applicazione...
Senza inviare su console messaggi a cui l'utente
finale non è interessato
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Eccezioni C++
Abbreviazione per
“evento eccezionale”
Si verifica durante l’esecuzione
Rompe il normale flusso di istruzioni di un programma
Quando si verifica un errore in un metodo, il metodo lancia ( throw ) un’eccezione
Il metodo crea un certo tipo di eccezione, con info sull’errore e sulle condizioni in cui si è verificato
… e lo consegna all’ambiente di runtime
La piattaforma cerca qualcosa che catturi e gestisca
( catch ) l’eccezione
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Codici di errore?
Tradizionalmente, il C segnala lo stato con codici particolari
Alcune condizioni normali, altre eccezionali:
Es. EOF considerato normale?
Es. Canale di comunicazione chiuso bruscamente o errore su dispositivo = eccezione?
Design by Contract
Eccezione se non sono rispettate precondizioni
Una funzione (o un metodo pubblico) può lanciare una
eccezione se i parametri sono fuori dalle specifiche
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Vantaggi delle eccezioni
Il costrutto try / catch separa la gestione di casi eccezionali dal flusso normale
Esecuzione interrotta immediatamente nel punto in cui si verifica l'eccezione (viene abbandonato definitivamente il blocco try)
Inizia la ricerca di un blocco catch adeguato
Si salta all'esecuzione del blocco catch (e del codice seguente)
Eccezioni organizzate in una gerarchia di tipi
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
vector<int> integers(6);
try {
for (int i = 0; i < 100; ++i) { integers.at(i) = i;
}
} catch (out_of_range& e) {
cerr << "Exception: " << e.what() << endl;
}
Esempio: out of range
Il metodo at controlla il range L'operatore [] no!
Il metodo at controlla il range L'operatore [] no!
what restituisce cstring Il ciclo for si interrompe
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
try {
ifstream file;
file.exceptions(ios::failbit | ios::badbit);
file.open("test.txt");
string buf;
while (getline(file, buf)) {
cout << "Read: " << buf << endl;
}
} catch (ios::failure& e) {
cerr << "File exception: " << e.what() << endl;
}
Esempio: stream
Eccezioni introdotte in C++ dopo gli stream
Bisogna abilitarle!
Eccezioni introdotte in C++ dopo gli stream
Bisogna abilitarle!
Il blocco catch Il blocco catch
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
class MyException : public exception { const char* what() {
return "My C++ exception";
} };
int main() { try {
// ...
throw MyException();
// ...
} catch(MyException& e) {
cerr << e.what() << std::endl;
} catch(exception e) { //Other errors
} }
Esempio: nuova eccezione
L'istruzione throw lancia una eccezione
L'istruzione throw lancia una eccezione
Nuova sottoclasse di exception (dove what
è definito virtual) Nuova sottoclasse di exception (dove what
è definito virtual)
Se ci sono diversi blocchi catch (tipi diversi)
Se ci sono diversi blocchi catch (tipi diversi)
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Gerarchia di eccezioni
Possibile definire ulteriori tipi di eccezione
Nuove sottoclassi nella gerarchia
logic_failure: bug, errore nel programma
runtime_error: errore in esecuzione
(condizioni esterne)
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Ricerca gestore di eccezioni
Dal metodo dove si verifica l’errore...
In ordine inverso rispetto a invocazioni
Il primo gestore,
appropriato per il tipo di eccezione, la cattura (catch)
Se non c’è un gestore appropriato, il
programma termina
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Stack delle chiamate
Call stack
Lista ordinata di metodi invocati al momento dell’errore
Exception handler
La piattaforma cerca
nel call stack un blocco
di codice che possa
gestire l’eccezione
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/
Catch or specify?
Il C++ (a differenza di Java) non obbliga alla gestione delle eccezioni
Nessun elenco esplicito di eccezioni lanciate
all'esterno da una funzione (C++11, deprecated)
void append(int x) throw (lenght_error) {
// … }
È possibile (ma sconsigliato) lanciare qualsiasi dato (anche int o cstring) come eccezione
try {
throw "Two many elements"; // don't do!
uolo – Fondamenti di informaticauolo – Fondamenti di informatica neria dell'informazione – UniPRegneria dell'informazione – UniPR w.ce.unipr.it/people/tomamic/w.ce.unipr.it/people/tomamic/