SlideShare a Scribd company logo
Array
Ilio Catallo – info@iliocatallo.it
Outline
¤ Introduzione agli array
¤ Array e puntatori
¤ Array e funzioni
¤ Array multidimensionali
¤ Array e iteratori
Introduzione agli array
Che cos’è un array?
¤ Un array si definisce specificandone:
¤ Il tipo dato comune ad ogni cella
¤ Il nome dell’array
¤ La sua dimensione
Un array è un contenitore di oggetti sequenziali
di un singolo tipo dato e di dimensione fissa
int numbers[5]; // an array of five int’s named ‘numbers’
¤ Il compilatore riserva il quantitativo di memoria
necessaria per accomodare 5 elementi di tipo int
¤ Le celle riservate sono contigue
¤ Ogni oggetto nell’array numbers è associato ad un
indice, che permette di accedere all’oggetto
¤ L’indice 0 è associato al primo elemento, l’indice 4 all’ultimo
Rappresentazione in memoria
numbers:
Assegnamento ed inizializzazione
¤ Cosa è possibile fare:
¤ Inizializzare un array con una lista di inizializzazione
int numbers[] = {1, 7, 13}; // ok, initialization list
Assegnamento ed inizializzazione
¤ Cosa non è possibile fare:
¤ Inizializzare un array come una copia di un’altro array
¤ Assegnare un array
int numbers[] = {1, 7, 13};
int other_numbers[] = numbers // error, copy initialization
int more_numbers[3];
more_numbers[] = {1, 7, 13} // error, assignment
Array non inizializzati
¤ Se in un una funzione si definisce un array senza
inizializzarlo, il valore iniziale degli elementi dipende dal
loro tipo T
¤ Se T è un tipo predefinito, gli elementi sono inizializzati a
default (default initialization)
¤ Altrimenti, si usa il costruttore di default di T per inizializzare
tutti gli elementi
¤ Se T non prevede un costruttore di default, il programma
non compila
Accedere agli elementi di un array
¤ Per accedere all’i-esimo elemento nell’array si utilizza
l’operatore [] (indexing operator*)
*anche detto subscript operator
int numbers[] = {1, 7, 13};
std::cout << "first element: ” << numbers[0] << std::endl;
Accessi fuori dall’intervallo
¤ Accessi fuori dall’intervallo ammissibile di un array sono
considerati undefined behavior
¤ Il programma compila, ma non è possibile prevedere cosa
accadrà dopo aver effettuato l’accesso errato
int numbers[3];
std::cout << numbers[100]; // undefined behavior
Accessi fuori dall’intervallo
¤ A differenza di altri linguaggio, il C++ non segnala in fase
d’esecuzione questo tipo di errore
int numbers[3];
std::cout << numbers[100]; // undefined behavior
Tipo dato degli elementi di un array
¤ Ogni elemento dell’array è del tipo specificato al
momento della definizione dell’array
¤ È possibile manipolare i singoli elementi di numbers come
una qualsiasi altra variabile di tipo int
int numbers[] = {1, 7, 13};
int x = numbers[2]; // initialize the int variable
// ‘x’ with another int
// variable (numbers[2])
Tipo dato di un array
¤ Quando definiamo un array, specifichiamo il tipo dato
dei singoli elementi:
¤ int non denota il tipo dato di numbers, bensì il tipo dato
dei suoi elementi numbers[0]…numbers[4]
int numbers[5]; // an array of five int’s named ‘numbers’
Tipo dato di un array
¤ Eppure numbers è una variabile, e come tale deve
avere un tipo dato
int numbers[5]; // an array of five int’s named ‘numbers’
Qual è il tipo dato di un array?
Tipo dato di un array
¤ Il tipo array è un tipo dato composto, in quanto dipende
da due fattori distinti:
¤ Il tipo dato T degli elementi
¤ Il numero di elementi m
Per un tipo dato T, T[m] è il tipo dato array di m elementi di tipo T
Tipo dato di un array
¤ Esempio: Il tipo dato di numbers è int[5], cioè
“array di 5 elementi di tipo int”
int numbers[5]; // an array of five int’s named ‘numbers’
Importanza del tipo composto
¤ È sufficiente che una sola delle due quantità (tipo T,
dimensione m) cambi per cambiare il tipo dato dell’array
¤ numbers e other_numbers non sono variabili dello
stesso tipo:
¤ numbers è di tipo int[5]
¤ other_numbers è di tipo int[10]
int numbers[5]; // numbers is of type int[5]
char letters[5]; // letters is of type char[5]
int other_numbers[10]; // other_numbers is of type int[10]
int other_letters[10]; // other_letters is of type char[10]
Dimensioni di un array
¤ La dimensione m è parte del tipo dato dell’array e deve
quindi essere nota a tempo di compilazione (compile-
time)
¤ Le uniche quantità che il compilatore può conoscere
prima che il codice venga eseguito sono le espressioni
costanti
int numbers[5];
5 è un letterale ed è
quindi un’espressione
costante, perchè noto a
compile-time
Dimensioni di un array
¤ Un’espressione costante può essere memorizzata in una
variabile costante, usando:
¤ il qualifier const
¤ lo specifier constexpr (dal C++11)
Dimensioni di un array
¤ Il tipo dato usato per mantenere la dimensione di un
array è size_t
constexpr size_t DIM = 5; // C++11
size_t const DIM = 5; // C++03
Dimensioni di un array
¤ size_t è un tipo intero senza segno in grado di
memorizzare la dimensione del più grande array
allocabile
constexpr size_t DIM = 5; // C++11
size_t const DIM = 5; // C++03
Array e puntatori
Puntatore al primo elemento
¤ Supponiamo di voler memorizzare in un puntatore
l’indirizzo del primo elemento di un array
¤ numbers[0] è un oggetto di tipo int ed ha un indirizzo,
possiamo memorizzare tale indirizzo in un puntatore a
int
int numbers[] = {1, 7, 13, 5, 9};
int* first_element_ptr = &numbers[0];
Puntatore al primo elemento
1 7 13 5 9numbers: int[5]
&numbers[0]first_elem_ptr: int*
Puntatore al primo elemento
¤ È possibile ottenere il l’indirizzo del primo elemento di un
array utilizzando un’espressione compatta
¤ Dato un array, ad esempio:
¤ Le seguenti due espressioni sono equivalenti:
int numbers[] = {1, 7, 13, 5, 9};
int* first_element_ptr = &numbers[0];
int* first_element_ptr = numbers;
Indirizzo del
primo elemento
Nome
dell’array
Decadimento a puntatore
¤ Come può mai funzionare questa cosa?
¤ first_element_ptr è di tipo int*
¤ numbers è di tipo int[5]
int* first_element_ptr = numbers;
Decadimento a puntatore
¤ Il tipo int[5] viene implicitamente convertito a int*
¤ Il risultato di tale conversione è un puntatore al primo
elemento dell’array
int* first_element_ptr = numbers;
Decadimento a puntatore
¤ Questo fenomeno prende il nome di array-to-pointer
decay
int* first_element_ptr = numbers;
Decadimento a puntatore
¤ La conversione non trasforma l’array in un puntatore
¤ Le variabili non cambiano tipo, numbers sarà sempre un
int[5]
int* first_element_ptr = numbers;
Decadimento a puntatore
¤ Cosa accade?
¤ Viene creato un puntatore temporaneo di tipo int*,
risultato del decadimento di numbers
¤ Il contenuto di tale puntatore (cioè l’indirizzo di numbers[0])
viene copiato in first_element_ptr
¤ Al termine dell’istruzione, il puntatore temporaneo viene
distrutto
int* first_element_ptr = numbers;
Decadimento a puntatore
¤ Nel valutare un’espressione che coinvolge un array di
tipo T[m], il compilatore:
¤ Se l’espressione è corretta, mantiene il tipo T[m]
¤ In caso contrario, converte T[m] a T*
int numbers[] = {1, 7, 13, 5, 9};
size_t numbers_size = sizeof(numbers); // numbers is
// treated as a
// int[5]
int* ptr_to_1st_element = numbers; // numbers is converted
// to int*
Perdita di informazione
¤ Il fenomeno si chiama decadimento perchè viene persa
dell’informazione
¤ Una volta convertito in puntatore, non è più possibile
conoscere la dimensione dell’array
¤ Ho solo un puntatore al primo elemento, ma quanti elementi
sono presenti nell’array?
¤ In altre parole, l’unico punto in comune tra i tipi dato
T[m] e T[n] è che entrambi decadono a T*
¤ I rispettivi decadimenti condividono lo stesso tipo dato T*
Aritmetica dei puntatori
¤ L’operatore [] permette di accedere e manipolare gli
elementi di un array
¤ Un secondo modo di interagire con gli elementi di un
array è utilizzare l’aritmetica dei puntatori
Aritmetica dei puntatori
¤ L’aritmetica dei puntatori si compone di un insieme di
operazione (aritmetiche) sui puntatori, in particolare:
¤ Incremento e decremento
¤ Addizione e sottrazione
¤ Confronto
¤ Assegnamento
Aritmetica dei puntatori
¤ Dato un puntatore ptr al primo elemento di un array,
l’espressione ptr + i restituisce un puntatore all’i-esimo
elemento dell’array
int numbers[] = {1, 7, 13, 5, 9};
int* first_element_ptr = numbers;
int* third_element_ptr = first_element_ptr + 2;
int* fifth_element_ptr = first_element_ptr + 4;
std::cout << "the third element is " << *third_element_ptr;
third_element_ptr è un
puntatore, per ottenere il
valore puntatato serve
l’operatore di indirezione *
Aritmetica dei puntatori
1 7 13 5 9numbers: int[5]
first_el_ptr:
first_el_ptr + 2 first_el_ptr + 4
=
fifth_el_ptr:
=
third_el_ptr: int*
Aritmetica dei puntatori
¤ Grazie al decadimento è possibile evitare l’uso di variabili
d’appoggio (come first_element_ptr):
¤ Le parentesi sono importanti
¤ *numbers + 4 è equivalente a numbers[0] + 4
¤ *(numbers + 4) è equivalente a numbers[4]
int numbers[] = {1, 7, 13, 5, 9};
std::cout << "the third element is " << *(numbers + 2);
std::cout << "the fifth element is " << *(numbers + 4);
Indexing operator vs.
aritmetica dei puntatori
¤ L’operatore [] è definito in termini di aritmetica dei
puntatori
¤ L’operatore [] è dunque una scrittura sintetica per
effettuare una somma su puntatore
Dato un array a ed un indice i,
l'operazione a[i] è implementata come *(a + i)
Indexing operator vs.
aritmetica dei puntatori
¤ L’operatore [] è in realtà un operatore definito sui
puntatori (si può usare sugli array grazie al decadimento)
int* first_elem_ptr = numbers;
std::cout << first_elem_ptr[3]; // implemented as
// *(first_elem_ptr + 3)
Indexing operator vs.
aritmetica dei puntatori
¤ Le due seguenti scritture sono equivalenti (la somma è
commutativa)
std::cout << numbers[2]; // implemented as *(numbers + 2)
std::cout << 2[numbers]; // implemented as *(2 + numbers)
Gli array non sono puntatori
¤ RICORDA: Gli array non sono puntatori
¤ Sono due tipi dati distinti, anche se strettamente legati
¤ Per convincersene è sufficiente notare che la loro
rappresentazione in memoria è diversa
…a: T[m]
ptr: T*
0 m-1
Array e funzioni
La funzione sum_int_array
¤ Vogliamo scrivere una funzione sum_int_array che
restituisca la somma dei valori contenuti in un array di
interi
int main() {
int numbers[] = {1, 7, 13, 5, 9};
int sum = sum_int_array(numbers);
std::cout << ”the elements sum up to " << sum
<< std::endl;
}
Viene stampato 35
Passare array a funzioni
¤ Non è possibile passare ad una funzione un array per
copia
¤ Non è possibile inizializzare l’array della funzione
chiamata copiando il contenuto dell’array della funzione
chiamante
Passaggio per indirizzo
¤ Nel passaggio per indirizzo viene fornita in ingresso alla
funzione chiamata una copia dell’indirizzo del parametro
che si vuole passare
¤ IDEA: fare in modo che sum_int_array riceva in
ingresso:
¤ Un puntatore alla prima celladell’array
¤ La dimensione dell’array
int sum_int_array(int* array, size_t dim_array);
Passaggio per indirizzo
¤ La funzione chiamante fornisce l’indirizzo del primo
elemento dell’array e la dimensione dell’array
int main() {
int numbers[] = {1, 7, 13, 5, 9};
int sum = sum_int_array(numbers, 5);
}
Il 1° parametro in ingresso a
sum_int_array è un
puntatore, quindi l’array
numbers decade a int*
int sum_int_array(int* array, size_t dim_array);
Passaggio per indirizzo
¤ Grazie al decadimento, è possibile usare il nome
dell’array per ottenere l’indirizzo del primo elemento
int main() {
int numbers[] = {1, 7, 13, 5, 9};
int sum = sum_int_array(numbers, 5);
}
Il 1° parametro in ingresso a
sum_int_array è un
puntatore, quindi l’array
numbers decade a int*
int sum_int_array(int* array, size_t dim_array);
Passaggio per indirizzo
¤ L’implementazione di sum_int_array è dunque
¤ L’operatore [] ci permette di manipolare il puntatore array
con la stessa sintassi che useremmo per un vero array
int sum_int_array(int* array, size_t dim_array) {
int sum = 0;
for (size_t i = 0; i < dim_array; ++i)
sum += array[i];
return sum;
}
Sintassi alternativa
¤ Esiste una sintassi alternativa per acquisire l’indirizzo del
primo elemento di un array
¤ I tre seguenti prototipi di sum_int_array sono equivalenti:
¤ NOTA: tale equivalenza vale unicamente quando si dichiara
una funzione
int sum_int_array(int* array, size_t dim_array);
int sum_int_array(int array[], size_t dim_array);
int sum_int_array(int array[5], size_t dim_array);
Sintassi alternativa
¤ L’utilizzo di uno dei due prototipi alternativi non significa
che l’array verrà passato per copia
¤ la variabile array è di tipo int*, a prescindere da quale
scrittura si utilizzi
¤ I prototipi alternativi danno l’illusione di agire su degli array
¤ Sono una delle cause della confusione tra array e puntatori
int sum_int_array(int array[], size_t dim_array);
int sum_int_array(int array[5], size_t dim_array);
Array multidimensionali
Array multidimensionali
¤ Gli array multidimensionali permettono estendere il
concetto di array a più di una dimensione
1 7 14
8 6 12
27 32 5
Array multidimensionali
¤ Nei normali array è sufficiente un solo indice per
identificare un elemento dell’array
¤ Negli array multidimensionali sono necessari tanti indici
quante dimensioni
1 7 14
8 6 12
27 32 5
indice di
riga i
indice di
colonna j
Array di array
1 7 14
8 6 12
27 32 5
1 7 14
8 6 12
27 32 5
! Array multidimensionale Array di array
Array di array
¤ In C++ non esistono array multidimensionali
¤ Gli array multidimensionali vengono realizzati mediante
array di array, cioè array i cui elementi sono a loro volta
array
Array di array
¤ Come per ogni array si definisce il numero di elementi
¤ Ogni elemento è però a sua volta un array
¤ Bisogna specificare una seconda quantità: il numero di
elementi in ogni sotto-array
int matrix[4][3]; // matrix is an array of 4 elements;
// each element is a int[3]
Array di array
¤ Esempio: matrix è un array di 4 elementi di tipo int[3]
¤ È la dimensione più interna che determina il numero di
sotto-array
int matrix[4][3];
Array di array
¤ L’uso di alias per i tipi dato può aiutarci a rendere più
chiaro il concetto
¤ matrix_row è un altro nome per il tipo int[3]
using matrix_row = int[3];
Array di array
¤ L’uso di alias per i tipi dato può aiutarci a rendere più
chiaro il concetto
¤ Così che matrix sia definibile come:
matrix_row matrix[4]; // an array of 4 elements of type
// matrix_row (i.e., of int[3])
using matrix_row = int[3];
Rappresentazione in memoria
¤ Abbiamo introdotto due rappresentazioni per gli array
multidimensionali
1 7 14
8 6 12
27 32 5
1 7 14
8 6 12
27 32 5
!
Rappresentazione in memoria
¤ Tali rappresentazioni sono intuitive, ma non riflettono
come un array multidimensionale è realmente
memorizzato in memoria
1 7 14
8 6 12
27 32 5
1 7 14
8 6 12
27 32 5
!
Rappresentazione in memoria
¤ Sappiamo che la memoria è modellata come una
sequenza di celle di memoria
¤ Gli array multidimensionale sono dunque memorizzati
come una sequenza di celle contigue
matrix: 1 7 14 8 16 12 27 32 5
matrix[0] matrix[1] matrix[2]
Inizializzazione
¤ Gli array multidimensionali possono essere inizializzati
mediante una lista di inizializzazione
¤ Le parentesi {} demarcano l’inizio e la fine di ogni riga
¤ Una scrittura equivalente (anche se meno leggibile):
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
int matrix[3][3] = {1, 7, 14, 8, 16, 12, 27, 32, 5};
Accedere agli elementi
¤ Per accedere all’(i,j)-esimo elemento si utilizza una
sequenza di operatori []
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
std::cout << "element (2,2): " << matrix[2][2];
Puntatore al primo elemento
¤ Supponiamo di voler memorizzare in un puntatore
l’indirizzo del primo elemento di un array multidim.
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
Puntatore al primo elemento
¤ matrix è un array di righe
¤ matrix[0] è di tipo int[3] (prima riga della matrice)
¤ Per salvarne l’indirizzo, è necessario un puntatore a int[3]
¤ Come si definisce un puntatore a tipo T[m]?
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
Puntatore ad array
¤ La sintassi per dichiarare un puntatore ad array è
leggermente diversa da quella usata fino ad adesso:
¤ Le parentesi sono importanti
int numbers[] = {1, 7, 13, 5, 9};
int (*numbers_ptr)[5] = &numbers; // numbers_ptr points to
// numbers
int* array_of_pointers[5] // array of 5 elements
// of type pointers to int
int (*pointer_to_array)[5] // pointer to an array
// of 5 elements of type int
Puntatore ad array
1 7 13 5 9 int[5]
&numbersnumbers_ptr: int(*)[5]
numbers:
Puntatore al primo elemento
¤ Possiamo ottenere un puntatore al primo elemento di un
array multidimensionale come:
¤ Ovviamente possiamo usare il decadimento:
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
int (*ptr_to_first_row)[3] = &matrix[0];
int (*ptr_to_first_row)[3] = matrix;
Puntatore al primo elemento
matrix: int[3][3]
&matrix[0]ptr_to_first_row: int(*)[3]
!
27 32 5
!
1 7 14
!
27 32 5
!
Alias per i sotto-array
¤ L’uso di alias per i tipi dato può nuovamente aiutarci a
rendere più leggibile il codice:
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
using matrix_row = int[3];
matrix_row* ptr_to_first_row = matrix;
Aritmetica dei puntatori
¤ L’aritmetica dei puntatori è definita anche su array
multidim.
¤ matrix è un array di righe
¤ Ogni elemento dell’array matrix è una riga della matrice
¤ Spostarsi di un elemento vuol dire passare alla riga successiva
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
using matrix_row = int[3];
matrix_row* ptr_to_first_row = matrix;
matrix_row* ptr_to_second_row = ptr_to_first_row + 1;
matrix_row* ptr_to_third_row = ptr_to_first_row + 2;
Aritmetica dei puntatori
matrix: int[3][3]
ptr_to_first_row
int(*)[3]
!
27 32 5
!
1 7 14
!
27 32 5
!
ptr_to_second_row ptr_to_third_row
=
ptr_to_first_row + 1
=
ptr_to_first_row + 2
Aritmetica dei puntatori
¤ Dato un puntatore ad una riga dell’array multidim.
¤ Si dereferenzia il puntatore per ottenere la riga
¤ Si utilizza l’aritmetica dei puntatori per per ottenere un
particolare elemento della riga
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
using matrix_row = int[3];
matrix_row* ptr_to_third_row = matrix + 2;
std::cout << "element (2,2): " << *(*ptr_to_third_row + 2);
terza riga dell’array multidim.
terzo elemento della terza riga
Aritmetica dei puntatori
¤ Grazie al decadimento, possiamo combinare le due
operazioni aritmetiche per ottenere un elemento
dell’array multidimensionale
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
using matrix_row = int[3];
matrix_row* ptr_to_third_row = matrix + 3;
std::cout << "element (2,2): " << *(*(matrix + 2) + 2);
terza riga dell’array multidim.
terzo elemento della terza riga
Indexing operator vs.
aritmetica dei puntatori
¤ Il comportamento dell’operatore [] rimane invariato
¤ Non è una nuova definizione dell’operatore, le due
operazioni vengono solo eseguite in cascata
¤ Si può pensare ad a[i][j] come (a[i])[j]:
¤ Si estrae la riga i-esima
¤ Da questa si seleziona il j-esimo elemento
Dato un array multdimensionale a e due indici i e j,
l'operazione a[i][j] è implementata come *(*(a + i) + j)
Passare array multidimensionali
a funzioni
¤ Supponiamo di voler scrivere una funzione
sum_int_matrix che sommi i valori di un array multidim.
di interi
int main () {
int matrix[3][3] = {{1, 7, 14},
{8, 16, 12},
{27, 32, 5}};
int sum = sum_int_matrix(matrix);
std::cout << "the elements sum up to " << sum
<< std::endl;
}
Passaggio per indirizzo
¤ IDEA: fare in modo che sum_int_matrix accetti un
puntatore alla prima riga
¤ Un puntatore alla prima riga permette di:
¤ Muoversi tra gli elementi della stessa riga
¤ Muoversi tra righe successive
int sum_int_matrix(int (*matrix)[3], size_t row_num);
Puntatore ad un array di 3
elementi di tipo int, cioè un
puntatore ad un riga
dell’array multidimensionale
Passaggio per indirizzo
¤ Quando si passano array multidim. tutte le dimensioni
tranne la prima devono essere note a compile-time
¤ L’accesso ad un array multidim. di tipo T[m][n] avviene
mediante un puntatore a tipo T[n]
¤ L’uso del puntatore ci permette di non conoscere m, ma il
valore n deve comunque essere noto
int sum_int_matrix(int (*matrix)[3], size_t row_num);
int sum_int_array(int* array, size_t dim_array);
In caso di array
nessuna
dimensione è
nota compile-
time
Il numero di elementi in
ogni riga deve essere
noto a compile-time
Passaggio per indirizzo
¤ L’implementazione di sum_int_matrix è dunque:
¤ L’operatore [] ci permette di manipolare il puntatore
matrix con la stessa sintassi che useremmo per un vero
array multidimensionale
int sum_int_matrix(int (*matrix)[3], size_t row_num) {
int sum = 0;
for (size_t i = 0; i < row_num; ++i)
for (size_t j = 0; j < 3; ++j)
sum += matrix[i][j];
return sum;
}
Sintassi alternativa
¤ Come per gli array, esiste una sintassi alternativa per
acquisire l’indirizzo della prima riga di un array multidim.
¤ I tre seguenti prototipi di sum_int_matrix sono
equivalenti:
¤ NOTA: tale equivalenza vale unicamente quando si
dichiara una funzione
int sum_int_matrix(int (*matrix)[3], size_t row_num);
int sum_int_matrix(int matrix[][3], size_t row_num);
int sum_int_matrix(int matrix[3][3], size_t row_num);
Array e iteratori
Container
¤ Esempi:
Un array è un contenitore di oggetti sequenziali
di un singolo tipo dato e di dimensione fissa
Un contenitore è un oggetto in grado di memorizzare altri oggetti
(detti elementi)
Un vector è un contenitore di oggetti sequenziali
di un singolo tipo dato e di dimensione variabile
Container
¤ Esempi di container:
¤ Array
¤ std::vector
¤ std::map
¤ std::multimap
¤ std::unordered_map
¤ std::set
¤ std::unordered_set
¤ std::multiset
¤ std::list
Iteratori
¤ Come suggerito dal nome, gli iteratori sono utilizzati per
iterare (scorrere) tra gli elementi di un container
¤ In questo modo:
¤ Il container ha il solo compito di utilizzare una strategia di
memorizzazione per preservare gli elementi in memoria
¤ L’iteratore ha il solo compito di fornire uno strumento di
accesso agli elementi
Iteratori
¤ Ogni iteratore è associato ad un elemento del
corrispettivo container
1 7 13 5 9numbers:
it_1st_elem
int[5]
it_3rd_elem
Iteratore di inizio e fine
¤ Ogni iteratore è associato ad un elemento del
corrispettivo container
¤ In particolare, per ogni container identifichiamo due
iteratori speciali:
¤ Un iteratore posizionato in corrispondenza del 1° elemento
¤ Un iteratore in posizione successiva all’ultimo elemento
Iteratore di inizio e fine
1 7 13 5 9numbers:
begin_iterator
int[5]
end_iterator
Iteratore di inizio e fine
¤ Il C++11/14 fornisce due funzioni per ottenere facilmente
entrambi gli iteratori:
auto begin_it = std::begin(numbers);
auto end_it = std::end(numbers);
Iteratore
¤ Si può chiedere ad un iteratore:
¤ di recuperare un elemento
¤ di muoversi da un elemento all’altro
Recuperare un elemento
¤ Ogni iteratore è associato ad un elemento del
corrispettivo container
¤ Dato un iteratore, è possibile ottenere il valore a lui
associato
auto begin_it = std::begin(numbers);
std::cout << "the first element of numbers is: "
<< *begin_it << std::endl;
Anteponendo l’asterisco
otteniamo il valore associato
all’iteratore begin_it
Muoversi da un elemento all’altro
¤ Possiamo usare l’operazione aritmetica di somma per
spostare l’iteratore di una posizione
auto it = std::begin(numbers);
std::cout << "first element: " << *it << std::endl;
++it;
std::cout << "second element: " << *it << std::endl;
Sommando +1 al valore
dell’iteratore mi sposta alla
posizione successiva
Muoversi da un elemento all’altro
1 7 13 5 9numbers:
it
int[5]
++it
Muoversi da un elemento all’altro
1 7 13 5 9numbers:
it
int[5]
Iteratori
¤ Un iteratore è una generalizzazione del concetto di
puntatore
¤ In particolare, come con i puntatori:
¤ Un iteratore è un oggetto che punta ad un altro oggetto
¤ L’elemento puntato è recuperabile mediante l’operatore *
¤ È possibile muoversi puntare all’elemento successivo
mediante operazioni aritmetiche
Navigare l’array
¤ Una volta disponibili gli iteratori di inizio e di fine è
possibile navigare l’array
for (auto it = begin_it; it != end_it; ++it)
std::cout << *it << std::endl;
1 7 13 5 9numbers:
begin_it int*
int[5]
end_itit
Algoritmi standard
¤ Gli iteratori possono essere utilizzati per compiere una
moltitudine di operazioni sui container
¤ Tutti gli algoritmi standard del C++ accettano in ingresso
una coppia di iteratori
¤ La coppia delimita la porzione del container su cui si vuole
agire
¤ In questo modo ogni algoritmo può essere usato con un
qualsiasi container, purchè esponga degli iteratori
Algoritmi standard
¤ Esempio: copiare un container
¤ Esempio: sommare i valori in un container
¤ Il codice non sarebbe cambiato anche se numbers fosse
stato un vector o un set
int other_numbers[5];
std::copy(std::begin(numbers),
std::end(numbers), std::begin(other_numbers));
int sum = std::accumulate(std::begin(numbers),
std::end(numbers), 0);
Bibliografia
Bibliografia
¤ S. B. Lippman, J. Lajoie, B. E. Moo, C++ Primer (5th Ed.)
¤ B. Stroustrup, The C++ Programming Language (4th Ed.)
¤ The Gang of Four, Design Patterns - Elements of Reusable
Object Oriented Software
¤ HP, Standard Template Library Programmer's Guide
https://www.sgi.com/tech/stl/
¤ Stackoverflow FAQ, “How do I use arrays in C++?”
http://stackoverflow.com/questions/4810664/how-do-i-use-
arrays-in-c

More Related Content

What's hot (20)

PPTX
String In C Language
Simplilearn
 
PPT
String c
thirumalaikumar3
 
PPT
6 Vettori E Matrici
guest60e9511
 
PPTX
Pointer in C
bipchulabmki
 
PPTX
C programming - String
Achyut Devkota
 
PPTX
C data type format specifier
Sandip Sitäulä
 
PDF
Introduction to Input/Output Functions in C
Thesis Scientist Private Limited
 
PDF
13. Pointer and 2D array
Gem WeBlog
 
PDF
STRINGS IN C MRS.SOWMYA JYOTHI.pdf
SowmyaJyothi3
 
PPTX
Structure in C language
CGC Technical campus,Mohali
 
PPT
Strings
Mitali Chugh
 
PPTX
Data Types In C
Simplilearn
 
PPT
Strings in c
vampugani
 
PPTX
Strings in C language
P M Patil
 
PPT
Structure c
thirumalaikumar3
 
PDF
C Pointers
omukhtar
 
PPTX
Array Of Pointers
Sharad Dubey
 
PPTX
Pointers in c language
Tanmay Modi
 
PDF
MANAGING INPUT AND OUTPUT OPERATIONS IN C MRS.SOWMYA JYOTHI.pdf
SowmyaJyothi3
 
PPTX
POINTERS IN C
Neel Mungra
 
String In C Language
Simplilearn
 
6 Vettori E Matrici
guest60e9511
 
Pointer in C
bipchulabmki
 
C programming - String
Achyut Devkota
 
C data type format specifier
Sandip Sitäulä
 
Introduction to Input/Output Functions in C
Thesis Scientist Private Limited
 
13. Pointer and 2D array
Gem WeBlog
 
STRINGS IN C MRS.SOWMYA JYOTHI.pdf
SowmyaJyothi3
 
Structure in C language
CGC Technical campus,Mohali
 
Strings
Mitali Chugh
 
Data Types In C
Simplilearn
 
Strings in c
vampugani
 
Strings in C language
P M Patil
 
Structure c
thirumalaikumar3
 
C Pointers
omukhtar
 
Array Of Pointers
Sharad Dubey
 
Pointers in c language
Tanmay Modi
 
MANAGING INPUT AND OUTPUT OPERATIONS IN C MRS.SOWMYA JYOTHI.pdf
SowmyaJyothi3
 
POINTERS IN C
Neel Mungra
 

Viewers also liked (12)

PPT
Importancia tecnología
patriciamorena27
 
PDF
Erid 1
A A
 
PPTX
Las tic características
Marbarire
 
PPTX
Lenguajes de programación
nao_1
 
PPTX
DESARROLLO DE MATERIALES ESCOLARES EN ECUADOR PARA UN MEJOR ENTENDIMIENTO DE ...
Patricio Bustos
 
PDF
営業資料Ver.1.0
A A
 
PDF
記帳代行 システム詳細のご説明
A A
 
PPTX
Scambio di variabili con le reference
Riccardo Monterisi
 
DOC
Super apostila de fisiologia do exercício
renatosnacer
 
PDF
Mirella Dapretto, PhD: Sensory Over-Responsivity in ASD: Insights from Neuroi...
Semel Admin
 
PDF
SMA IMPORTADORA
AVIVAR AVIVAR
 
PDF
Catalogo lazi & brizi2016
Wencedor Representações
 
Importancia tecnología
patriciamorena27
 
Erid 1
A A
 
Las tic características
Marbarire
 
Lenguajes de programación
nao_1
 
DESARROLLO DE MATERIALES ESCOLARES EN ECUADOR PARA UN MEJOR ENTENDIMIENTO DE ...
Patricio Bustos
 
営業資料Ver.1.0
A A
 
記帳代行 システム詳細のご説明
A A
 
Scambio di variabili con le reference
Riccardo Monterisi
 
Super apostila de fisiologia do exercício
renatosnacer
 
Mirella Dapretto, PhD: Sensory Over-Responsivity in ASD: Insights from Neuroi...
Semel Admin
 
SMA IMPORTADORA
AVIVAR AVIVAR
 
Catalogo lazi & brizi2016
Wencedor Representações
 
Ad

Similar to Array in C++ (17)

PPT
06 1 array_stringhe_typedef
Piero Fraternali
 
PDF
Puntatori e Riferimenti
Ilio Catallo
 
PDF
Lezione 16 (2 aprile 2012)
STELITANO
 
PDF
Lezione 13 (2 aprile 2012)
STELITANO
 
PDF
Lezione 13 (2 aprile 2012)
STELITANO
 
PDF
Linguaggio R, principi e concetti
Vincenzo De Maio
 
PDF
Lezione 12 (28 marzo 2012) puntatori vettori
STELITANO
 
PPT
13 Puntatori E Memoria Dinamica
guest60e9511
 
PDF
Lezione 15 (2 aprile 2012)
STELITANO
 
PPTX
Puntatori in C++
marckmart
 
PDF
Lezione 10 (21 marzo 2012)2
STELITANO
 
PPSX
Array
Mariangela Mone
 
PDF
10 - Programmazione: Tipi di dato strutturati
Majong DevJfu
 
PDF
12 - Programmazione: Array dinamici e puntatori
Majong DevJfu
 
PPT
Riepilogo Java C/C++
Pasquale Paola
 
PDF
Esercitazione 3 (14 marzo 2012)
STELITANO
 
PPT
Corso c++
Antonio Furone
 
06 1 array_stringhe_typedef
Piero Fraternali
 
Puntatori e Riferimenti
Ilio Catallo
 
Lezione 16 (2 aprile 2012)
STELITANO
 
Lezione 13 (2 aprile 2012)
STELITANO
 
Lezione 13 (2 aprile 2012)
STELITANO
 
Linguaggio R, principi e concetti
Vincenzo De Maio
 
Lezione 12 (28 marzo 2012) puntatori vettori
STELITANO
 
13 Puntatori E Memoria Dinamica
guest60e9511
 
Lezione 15 (2 aprile 2012)
STELITANO
 
Puntatori in C++
marckmart
 
Lezione 10 (21 marzo 2012)2
STELITANO
 
10 - Programmazione: Tipi di dato strutturati
Majong DevJfu
 
12 - Programmazione: Array dinamici e puntatori
Majong DevJfu
 
Riepilogo Java C/C++
Pasquale Paola
 
Esercitazione 3 (14 marzo 2012)
STELITANO
 
Corso c++
Antonio Furone
 
Ad

More from Ilio Catallo (20)

PDF
C++ Standard Template Library
Ilio Catallo
 
PDF
Regular types in C++
Ilio Catallo
 
PDF
Resource wrappers in C++
Ilio Catallo
 
PDF
Memory management in C++
Ilio Catallo
 
PDF
Operator overloading in C++
Ilio Catallo
 
PDF
Multidimensional arrays in C++
Ilio Catallo
 
PDF
Arrays in C++
Ilio Catallo
 
PDF
Pointers & References in C++
Ilio Catallo
 
PDF
Spring MVC - Wiring the different layers
Ilio Catallo
 
PDF
Java and Java platforms
Ilio Catallo
 
PDF
Spring MVC - Web Forms
Ilio Catallo
 
PDF
Spring MVC - The Basics
Ilio Catallo
 
PDF
Web application architecture
Ilio Catallo
 
PDF
Introduction To Spring
Ilio Catallo
 
PDF
Gestione della memoria in C++
Ilio Catallo
 
PDF
Java Persistence API
Ilio Catallo
 
PDF
JSP Standard Tag Library
Ilio Catallo
 
PDF
Internationalization in Jakarta Struts 1.3
Ilio Catallo
 
PDF
Validation in Jakarta Struts 1.3
Ilio Catallo
 
PDF
Introduction to Struts 1.3
Ilio Catallo
 
C++ Standard Template Library
Ilio Catallo
 
Regular types in C++
Ilio Catallo
 
Resource wrappers in C++
Ilio Catallo
 
Memory management in C++
Ilio Catallo
 
Operator overloading in C++
Ilio Catallo
 
Multidimensional arrays in C++
Ilio Catallo
 
Arrays in C++
Ilio Catallo
 
Pointers & References in C++
Ilio Catallo
 
Spring MVC - Wiring the different layers
Ilio Catallo
 
Java and Java platforms
Ilio Catallo
 
Spring MVC - Web Forms
Ilio Catallo
 
Spring MVC - The Basics
Ilio Catallo
 
Web application architecture
Ilio Catallo
 
Introduction To Spring
Ilio Catallo
 
Gestione della memoria in C++
Ilio Catallo
 
Java Persistence API
Ilio Catallo
 
JSP Standard Tag Library
Ilio Catallo
 
Internationalization in Jakarta Struts 1.3
Ilio Catallo
 
Validation in Jakarta Struts 1.3
Ilio Catallo
 
Introduction to Struts 1.3
Ilio Catallo
 

Recently uploaded (20)

PDF
Convivial Toolbox Generative Research for the Front End of Design Sanders
dbfgwsd7013
 
PDF
GIS for coastal zone management 1st Edition Darius J. Bartlett
vmlvdicyan1459
 
PDF
On The Republic And On The Laws Marcus Tullius Cicero
tmgdbwp558
 
PDF
Endovascular Intervention for Vascular Disease Principles and Practice 1st Ed...
ecyrbux1225
 
PDF
Nonlinear time series semiparametric and nonparametric methods 1st Edition Ji...
qvhcajae3274
 
PDF
Parasite Genomics Protocols 2nd Edition Christopher Peacock (Eds.)
ceqjojspsu7012
 
PDF
Download full ebook of Urban Health Steven Whitman instant download pdf
aiyifwhh358
 
PDF
Handbook of surface and nanometrology 1st Edition David J. Whitehouse
qywzgmvekg7088
 
PDF
Theories in Second Language Acquisition 2nd Edition Bill Vanpatten
dakcwdr215
 
PDF
Download full ebook of Eternity Row Viehl S L instant download pdf
nruebomj2316
 
PDF
Mechanism Machine Robotics And Mechatronics Sciences 1st Ed Rany Rizk
tlrgxhdb1583
 
PDF
River Diversions A Design Guide Fisher Karen Ramsbottom David
wildyfiney7t
 
PDF
Ageless Odyssey An Action Adventure Harem Fantasy Book 1 S Corbyn
gxubipaoc5753
 
PDF
Genomic Approaches for Cross Species Extrapolation in Toxicology 1st Edition ...
bblqruhf237
 
PDF
Postgresql 155 Documentation 155 The Postgresql Global Development Group
wfilecmlq435
 
PDF
Splatterpunk Bloodstains Bantry Jack Young Wile Garza Michelle Lason
yefeocqetc245
 
PDF
Historical Information Science An Emerging Unidiscipline 1st Edition Lawrence...
fjbhlzjnwe8836
 
PPTX
Anne in italiana version handmade p.pptx
3326634869
 
PDF
Inequality In Public School Admission In Urban China 1st Ed Jing Liu
hoczmiby1785
 
PDF
Techniques Technology and Civilization 1st Edition Marcel Mauss
beuvygsnb2172
 
Convivial Toolbox Generative Research for the Front End of Design Sanders
dbfgwsd7013
 
GIS for coastal zone management 1st Edition Darius J. Bartlett
vmlvdicyan1459
 
On The Republic And On The Laws Marcus Tullius Cicero
tmgdbwp558
 
Endovascular Intervention for Vascular Disease Principles and Practice 1st Ed...
ecyrbux1225
 
Nonlinear time series semiparametric and nonparametric methods 1st Edition Ji...
qvhcajae3274
 
Parasite Genomics Protocols 2nd Edition Christopher Peacock (Eds.)
ceqjojspsu7012
 
Download full ebook of Urban Health Steven Whitman instant download pdf
aiyifwhh358
 
Handbook of surface and nanometrology 1st Edition David J. Whitehouse
qywzgmvekg7088
 
Theories in Second Language Acquisition 2nd Edition Bill Vanpatten
dakcwdr215
 
Download full ebook of Eternity Row Viehl S L instant download pdf
nruebomj2316
 
Mechanism Machine Robotics And Mechatronics Sciences 1st Ed Rany Rizk
tlrgxhdb1583
 
River Diversions A Design Guide Fisher Karen Ramsbottom David
wildyfiney7t
 
Ageless Odyssey An Action Adventure Harem Fantasy Book 1 S Corbyn
gxubipaoc5753
 
Genomic Approaches for Cross Species Extrapolation in Toxicology 1st Edition ...
bblqruhf237
 
Postgresql 155 Documentation 155 The Postgresql Global Development Group
wfilecmlq435
 
Splatterpunk Bloodstains Bantry Jack Young Wile Garza Michelle Lason
yefeocqetc245
 
Historical Information Science An Emerging Unidiscipline 1st Edition Lawrence...
fjbhlzjnwe8836
 
Anne in italiana version handmade p.pptx
3326634869
 
Inequality In Public School Admission In Urban China 1st Ed Jing Liu
hoczmiby1785
 
Techniques Technology and Civilization 1st Edition Marcel Mauss
beuvygsnb2172
 

Array in C++

  • 2. Outline ¤ Introduzione agli array ¤ Array e puntatori ¤ Array e funzioni ¤ Array multidimensionali ¤ Array e iteratori
  • 4. Che cos’è un array? ¤ Un array si definisce specificandone: ¤ Il tipo dato comune ad ogni cella ¤ Il nome dell’array ¤ La sua dimensione Un array è un contenitore di oggetti sequenziali di un singolo tipo dato e di dimensione fissa int numbers[5]; // an array of five int’s named ‘numbers’
  • 5. ¤ Il compilatore riserva il quantitativo di memoria necessaria per accomodare 5 elementi di tipo int ¤ Le celle riservate sono contigue ¤ Ogni oggetto nell’array numbers è associato ad un indice, che permette di accedere all’oggetto ¤ L’indice 0 è associato al primo elemento, l’indice 4 all’ultimo Rappresentazione in memoria numbers:
  • 6. Assegnamento ed inizializzazione ¤ Cosa è possibile fare: ¤ Inizializzare un array con una lista di inizializzazione int numbers[] = {1, 7, 13}; // ok, initialization list
  • 7. Assegnamento ed inizializzazione ¤ Cosa non è possibile fare: ¤ Inizializzare un array come una copia di un’altro array ¤ Assegnare un array int numbers[] = {1, 7, 13}; int other_numbers[] = numbers // error, copy initialization int more_numbers[3]; more_numbers[] = {1, 7, 13} // error, assignment
  • 8. Array non inizializzati ¤ Se in un una funzione si definisce un array senza inizializzarlo, il valore iniziale degli elementi dipende dal loro tipo T ¤ Se T è un tipo predefinito, gli elementi sono inizializzati a default (default initialization) ¤ Altrimenti, si usa il costruttore di default di T per inizializzare tutti gli elementi ¤ Se T non prevede un costruttore di default, il programma non compila
  • 9. Accedere agli elementi di un array ¤ Per accedere all’i-esimo elemento nell’array si utilizza l’operatore [] (indexing operator*) *anche detto subscript operator int numbers[] = {1, 7, 13}; std::cout << "first element: ” << numbers[0] << std::endl;
  • 10. Accessi fuori dall’intervallo ¤ Accessi fuori dall’intervallo ammissibile di un array sono considerati undefined behavior ¤ Il programma compila, ma non è possibile prevedere cosa accadrà dopo aver effettuato l’accesso errato int numbers[3]; std::cout << numbers[100]; // undefined behavior
  • 11. Accessi fuori dall’intervallo ¤ A differenza di altri linguaggio, il C++ non segnala in fase d’esecuzione questo tipo di errore int numbers[3]; std::cout << numbers[100]; // undefined behavior
  • 12. Tipo dato degli elementi di un array ¤ Ogni elemento dell’array è del tipo specificato al momento della definizione dell’array ¤ È possibile manipolare i singoli elementi di numbers come una qualsiasi altra variabile di tipo int int numbers[] = {1, 7, 13}; int x = numbers[2]; // initialize the int variable // ‘x’ with another int // variable (numbers[2])
  • 13. Tipo dato di un array ¤ Quando definiamo un array, specifichiamo il tipo dato dei singoli elementi: ¤ int non denota il tipo dato di numbers, bensì il tipo dato dei suoi elementi numbers[0]…numbers[4] int numbers[5]; // an array of five int’s named ‘numbers’
  • 14. Tipo dato di un array ¤ Eppure numbers è una variabile, e come tale deve avere un tipo dato int numbers[5]; // an array of five int’s named ‘numbers’ Qual è il tipo dato di un array?
  • 15. Tipo dato di un array ¤ Il tipo array è un tipo dato composto, in quanto dipende da due fattori distinti: ¤ Il tipo dato T degli elementi ¤ Il numero di elementi m Per un tipo dato T, T[m] è il tipo dato array di m elementi di tipo T
  • 16. Tipo dato di un array ¤ Esempio: Il tipo dato di numbers è int[5], cioè “array di 5 elementi di tipo int” int numbers[5]; // an array of five int’s named ‘numbers’
  • 17. Importanza del tipo composto ¤ È sufficiente che una sola delle due quantità (tipo T, dimensione m) cambi per cambiare il tipo dato dell’array ¤ numbers e other_numbers non sono variabili dello stesso tipo: ¤ numbers è di tipo int[5] ¤ other_numbers è di tipo int[10] int numbers[5]; // numbers is of type int[5] char letters[5]; // letters is of type char[5] int other_numbers[10]; // other_numbers is of type int[10] int other_letters[10]; // other_letters is of type char[10]
  • 18. Dimensioni di un array ¤ La dimensione m è parte del tipo dato dell’array e deve quindi essere nota a tempo di compilazione (compile- time) ¤ Le uniche quantità che il compilatore può conoscere prima che il codice venga eseguito sono le espressioni costanti int numbers[5]; 5 è un letterale ed è quindi un’espressione costante, perchè noto a compile-time
  • 19. Dimensioni di un array ¤ Un’espressione costante può essere memorizzata in una variabile costante, usando: ¤ il qualifier const ¤ lo specifier constexpr (dal C++11)
  • 20. Dimensioni di un array ¤ Il tipo dato usato per mantenere la dimensione di un array è size_t constexpr size_t DIM = 5; // C++11 size_t const DIM = 5; // C++03
  • 21. Dimensioni di un array ¤ size_t è un tipo intero senza segno in grado di memorizzare la dimensione del più grande array allocabile constexpr size_t DIM = 5; // C++11 size_t const DIM = 5; // C++03
  • 23. Puntatore al primo elemento ¤ Supponiamo di voler memorizzare in un puntatore l’indirizzo del primo elemento di un array ¤ numbers[0] è un oggetto di tipo int ed ha un indirizzo, possiamo memorizzare tale indirizzo in un puntatore a int int numbers[] = {1, 7, 13, 5, 9}; int* first_element_ptr = &numbers[0];
  • 24. Puntatore al primo elemento 1 7 13 5 9numbers: int[5] &numbers[0]first_elem_ptr: int*
  • 25. Puntatore al primo elemento ¤ È possibile ottenere il l’indirizzo del primo elemento di un array utilizzando un’espressione compatta ¤ Dato un array, ad esempio: ¤ Le seguenti due espressioni sono equivalenti: int numbers[] = {1, 7, 13, 5, 9}; int* first_element_ptr = &numbers[0]; int* first_element_ptr = numbers; Indirizzo del primo elemento Nome dell’array
  • 26. Decadimento a puntatore ¤ Come può mai funzionare questa cosa? ¤ first_element_ptr è di tipo int* ¤ numbers è di tipo int[5] int* first_element_ptr = numbers;
  • 27. Decadimento a puntatore ¤ Il tipo int[5] viene implicitamente convertito a int* ¤ Il risultato di tale conversione è un puntatore al primo elemento dell’array int* first_element_ptr = numbers;
  • 28. Decadimento a puntatore ¤ Questo fenomeno prende il nome di array-to-pointer decay int* first_element_ptr = numbers;
  • 29. Decadimento a puntatore ¤ La conversione non trasforma l’array in un puntatore ¤ Le variabili non cambiano tipo, numbers sarà sempre un int[5] int* first_element_ptr = numbers;
  • 30. Decadimento a puntatore ¤ Cosa accade? ¤ Viene creato un puntatore temporaneo di tipo int*, risultato del decadimento di numbers ¤ Il contenuto di tale puntatore (cioè l’indirizzo di numbers[0]) viene copiato in first_element_ptr ¤ Al termine dell’istruzione, il puntatore temporaneo viene distrutto int* first_element_ptr = numbers;
  • 31. Decadimento a puntatore ¤ Nel valutare un’espressione che coinvolge un array di tipo T[m], il compilatore: ¤ Se l’espressione è corretta, mantiene il tipo T[m] ¤ In caso contrario, converte T[m] a T* int numbers[] = {1, 7, 13, 5, 9}; size_t numbers_size = sizeof(numbers); // numbers is // treated as a // int[5] int* ptr_to_1st_element = numbers; // numbers is converted // to int*
  • 32. Perdita di informazione ¤ Il fenomeno si chiama decadimento perchè viene persa dell’informazione ¤ Una volta convertito in puntatore, non è più possibile conoscere la dimensione dell’array ¤ Ho solo un puntatore al primo elemento, ma quanti elementi sono presenti nell’array? ¤ In altre parole, l’unico punto in comune tra i tipi dato T[m] e T[n] è che entrambi decadono a T* ¤ I rispettivi decadimenti condividono lo stesso tipo dato T*
  • 33. Aritmetica dei puntatori ¤ L’operatore [] permette di accedere e manipolare gli elementi di un array ¤ Un secondo modo di interagire con gli elementi di un array è utilizzare l’aritmetica dei puntatori
  • 34. Aritmetica dei puntatori ¤ L’aritmetica dei puntatori si compone di un insieme di operazione (aritmetiche) sui puntatori, in particolare: ¤ Incremento e decremento ¤ Addizione e sottrazione ¤ Confronto ¤ Assegnamento
  • 35. Aritmetica dei puntatori ¤ Dato un puntatore ptr al primo elemento di un array, l’espressione ptr + i restituisce un puntatore all’i-esimo elemento dell’array int numbers[] = {1, 7, 13, 5, 9}; int* first_element_ptr = numbers; int* third_element_ptr = first_element_ptr + 2; int* fifth_element_ptr = first_element_ptr + 4; std::cout << "the third element is " << *third_element_ptr; third_element_ptr è un puntatore, per ottenere il valore puntatato serve l’operatore di indirezione *
  • 36. Aritmetica dei puntatori 1 7 13 5 9numbers: int[5] first_el_ptr: first_el_ptr + 2 first_el_ptr + 4 = fifth_el_ptr: = third_el_ptr: int*
  • 37. Aritmetica dei puntatori ¤ Grazie al decadimento è possibile evitare l’uso di variabili d’appoggio (come first_element_ptr): ¤ Le parentesi sono importanti ¤ *numbers + 4 è equivalente a numbers[0] + 4 ¤ *(numbers + 4) è equivalente a numbers[4] int numbers[] = {1, 7, 13, 5, 9}; std::cout << "the third element is " << *(numbers + 2); std::cout << "the fifth element is " << *(numbers + 4);
  • 38. Indexing operator vs. aritmetica dei puntatori ¤ L’operatore [] è definito in termini di aritmetica dei puntatori ¤ L’operatore [] è dunque una scrittura sintetica per effettuare una somma su puntatore Dato un array a ed un indice i, l'operazione a[i] è implementata come *(a + i)
  • 39. Indexing operator vs. aritmetica dei puntatori ¤ L’operatore [] è in realtà un operatore definito sui puntatori (si può usare sugli array grazie al decadimento) int* first_elem_ptr = numbers; std::cout << first_elem_ptr[3]; // implemented as // *(first_elem_ptr + 3)
  • 40. Indexing operator vs. aritmetica dei puntatori ¤ Le due seguenti scritture sono equivalenti (la somma è commutativa) std::cout << numbers[2]; // implemented as *(numbers + 2) std::cout << 2[numbers]; // implemented as *(2 + numbers)
  • 41. Gli array non sono puntatori ¤ RICORDA: Gli array non sono puntatori ¤ Sono due tipi dati distinti, anche se strettamente legati ¤ Per convincersene è sufficiente notare che la loro rappresentazione in memoria è diversa …a: T[m] ptr: T* 0 m-1
  • 43. La funzione sum_int_array ¤ Vogliamo scrivere una funzione sum_int_array che restituisca la somma dei valori contenuti in un array di interi int main() { int numbers[] = {1, 7, 13, 5, 9}; int sum = sum_int_array(numbers); std::cout << ”the elements sum up to " << sum << std::endl; } Viene stampato 35
  • 44. Passare array a funzioni ¤ Non è possibile passare ad una funzione un array per copia ¤ Non è possibile inizializzare l’array della funzione chiamata copiando il contenuto dell’array della funzione chiamante
  • 45. Passaggio per indirizzo ¤ Nel passaggio per indirizzo viene fornita in ingresso alla funzione chiamata una copia dell’indirizzo del parametro che si vuole passare ¤ IDEA: fare in modo che sum_int_array riceva in ingresso: ¤ Un puntatore alla prima celladell’array ¤ La dimensione dell’array int sum_int_array(int* array, size_t dim_array);
  • 46. Passaggio per indirizzo ¤ La funzione chiamante fornisce l’indirizzo del primo elemento dell’array e la dimensione dell’array int main() { int numbers[] = {1, 7, 13, 5, 9}; int sum = sum_int_array(numbers, 5); } Il 1° parametro in ingresso a sum_int_array è un puntatore, quindi l’array numbers decade a int* int sum_int_array(int* array, size_t dim_array);
  • 47. Passaggio per indirizzo ¤ Grazie al decadimento, è possibile usare il nome dell’array per ottenere l’indirizzo del primo elemento int main() { int numbers[] = {1, 7, 13, 5, 9}; int sum = sum_int_array(numbers, 5); } Il 1° parametro in ingresso a sum_int_array è un puntatore, quindi l’array numbers decade a int* int sum_int_array(int* array, size_t dim_array);
  • 48. Passaggio per indirizzo ¤ L’implementazione di sum_int_array è dunque ¤ L’operatore [] ci permette di manipolare il puntatore array con la stessa sintassi che useremmo per un vero array int sum_int_array(int* array, size_t dim_array) { int sum = 0; for (size_t i = 0; i < dim_array; ++i) sum += array[i]; return sum; }
  • 49. Sintassi alternativa ¤ Esiste una sintassi alternativa per acquisire l’indirizzo del primo elemento di un array ¤ I tre seguenti prototipi di sum_int_array sono equivalenti: ¤ NOTA: tale equivalenza vale unicamente quando si dichiara una funzione int sum_int_array(int* array, size_t dim_array); int sum_int_array(int array[], size_t dim_array); int sum_int_array(int array[5], size_t dim_array);
  • 50. Sintassi alternativa ¤ L’utilizzo di uno dei due prototipi alternativi non significa che l’array verrà passato per copia ¤ la variabile array è di tipo int*, a prescindere da quale scrittura si utilizzi ¤ I prototipi alternativi danno l’illusione di agire su degli array ¤ Sono una delle cause della confusione tra array e puntatori int sum_int_array(int array[], size_t dim_array); int sum_int_array(int array[5], size_t dim_array);
  • 52. Array multidimensionali ¤ Gli array multidimensionali permettono estendere il concetto di array a più di una dimensione 1 7 14 8 6 12 27 32 5
  • 53. Array multidimensionali ¤ Nei normali array è sufficiente un solo indice per identificare un elemento dell’array ¤ Negli array multidimensionali sono necessari tanti indici quante dimensioni 1 7 14 8 6 12 27 32 5 indice di riga i indice di colonna j
  • 54. Array di array 1 7 14 8 6 12 27 32 5 1 7 14 8 6 12 27 32 5 ! Array multidimensionale Array di array
  • 55. Array di array ¤ In C++ non esistono array multidimensionali ¤ Gli array multidimensionali vengono realizzati mediante array di array, cioè array i cui elementi sono a loro volta array
  • 56. Array di array ¤ Come per ogni array si definisce il numero di elementi ¤ Ogni elemento è però a sua volta un array ¤ Bisogna specificare una seconda quantità: il numero di elementi in ogni sotto-array int matrix[4][3]; // matrix is an array of 4 elements; // each element is a int[3]
  • 57. Array di array ¤ Esempio: matrix è un array di 4 elementi di tipo int[3] ¤ È la dimensione più interna che determina il numero di sotto-array int matrix[4][3];
  • 58. Array di array ¤ L’uso di alias per i tipi dato può aiutarci a rendere più chiaro il concetto ¤ matrix_row è un altro nome per il tipo int[3] using matrix_row = int[3];
  • 59. Array di array ¤ L’uso di alias per i tipi dato può aiutarci a rendere più chiaro il concetto ¤ Così che matrix sia definibile come: matrix_row matrix[4]; // an array of 4 elements of type // matrix_row (i.e., of int[3]) using matrix_row = int[3];
  • 60. Rappresentazione in memoria ¤ Abbiamo introdotto due rappresentazioni per gli array multidimensionali 1 7 14 8 6 12 27 32 5 1 7 14 8 6 12 27 32 5 !
  • 61. Rappresentazione in memoria ¤ Tali rappresentazioni sono intuitive, ma non riflettono come un array multidimensionale è realmente memorizzato in memoria 1 7 14 8 6 12 27 32 5 1 7 14 8 6 12 27 32 5 !
  • 62. Rappresentazione in memoria ¤ Sappiamo che la memoria è modellata come una sequenza di celle di memoria ¤ Gli array multidimensionale sono dunque memorizzati come una sequenza di celle contigue matrix: 1 7 14 8 16 12 27 32 5 matrix[0] matrix[1] matrix[2]
  • 63. Inizializzazione ¤ Gli array multidimensionali possono essere inizializzati mediante una lista di inizializzazione ¤ Le parentesi {} demarcano l’inizio e la fine di ogni riga ¤ Una scrittura equivalente (anche se meno leggibile): int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}}; int matrix[3][3] = {1, 7, 14, 8, 16, 12, 27, 32, 5};
  • 64. Accedere agli elementi ¤ Per accedere all’(i,j)-esimo elemento si utilizza una sequenza di operatori [] int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}}; std::cout << "element (2,2): " << matrix[2][2];
  • 65. Puntatore al primo elemento ¤ Supponiamo di voler memorizzare in un puntatore l’indirizzo del primo elemento di un array multidim. int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}};
  • 66. Puntatore al primo elemento ¤ matrix è un array di righe ¤ matrix[0] è di tipo int[3] (prima riga della matrice) ¤ Per salvarne l’indirizzo, è necessario un puntatore a int[3] ¤ Come si definisce un puntatore a tipo T[m]? int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}};
  • 67. Puntatore ad array ¤ La sintassi per dichiarare un puntatore ad array è leggermente diversa da quella usata fino ad adesso: ¤ Le parentesi sono importanti int numbers[] = {1, 7, 13, 5, 9}; int (*numbers_ptr)[5] = &numbers; // numbers_ptr points to // numbers int* array_of_pointers[5] // array of 5 elements // of type pointers to int int (*pointer_to_array)[5] // pointer to an array // of 5 elements of type int
  • 68. Puntatore ad array 1 7 13 5 9 int[5] &numbersnumbers_ptr: int(*)[5] numbers:
  • 69. Puntatore al primo elemento ¤ Possiamo ottenere un puntatore al primo elemento di un array multidimensionale come: ¤ Ovviamente possiamo usare il decadimento: int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}}; int (*ptr_to_first_row)[3] = &matrix[0]; int (*ptr_to_first_row)[3] = matrix;
  • 70. Puntatore al primo elemento matrix: int[3][3] &matrix[0]ptr_to_first_row: int(*)[3] ! 27 32 5 ! 1 7 14 ! 27 32 5 !
  • 71. Alias per i sotto-array ¤ L’uso di alias per i tipi dato può nuovamente aiutarci a rendere più leggibile il codice: int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}}; using matrix_row = int[3]; matrix_row* ptr_to_first_row = matrix;
  • 72. Aritmetica dei puntatori ¤ L’aritmetica dei puntatori è definita anche su array multidim. ¤ matrix è un array di righe ¤ Ogni elemento dell’array matrix è una riga della matrice ¤ Spostarsi di un elemento vuol dire passare alla riga successiva int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}}; using matrix_row = int[3]; matrix_row* ptr_to_first_row = matrix; matrix_row* ptr_to_second_row = ptr_to_first_row + 1; matrix_row* ptr_to_third_row = ptr_to_first_row + 2;
  • 73. Aritmetica dei puntatori matrix: int[3][3] ptr_to_first_row int(*)[3] ! 27 32 5 ! 1 7 14 ! 27 32 5 ! ptr_to_second_row ptr_to_third_row = ptr_to_first_row + 1 = ptr_to_first_row + 2
  • 74. Aritmetica dei puntatori ¤ Dato un puntatore ad una riga dell’array multidim. ¤ Si dereferenzia il puntatore per ottenere la riga ¤ Si utilizza l’aritmetica dei puntatori per per ottenere un particolare elemento della riga int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}}; using matrix_row = int[3]; matrix_row* ptr_to_third_row = matrix + 2; std::cout << "element (2,2): " << *(*ptr_to_third_row + 2); terza riga dell’array multidim. terzo elemento della terza riga
  • 75. Aritmetica dei puntatori ¤ Grazie al decadimento, possiamo combinare le due operazioni aritmetiche per ottenere un elemento dell’array multidimensionale int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}}; using matrix_row = int[3]; matrix_row* ptr_to_third_row = matrix + 3; std::cout << "element (2,2): " << *(*(matrix + 2) + 2); terza riga dell’array multidim. terzo elemento della terza riga
  • 76. Indexing operator vs. aritmetica dei puntatori ¤ Il comportamento dell’operatore [] rimane invariato ¤ Non è una nuova definizione dell’operatore, le due operazioni vengono solo eseguite in cascata ¤ Si può pensare ad a[i][j] come (a[i])[j]: ¤ Si estrae la riga i-esima ¤ Da questa si seleziona il j-esimo elemento Dato un array multdimensionale a e due indici i e j, l'operazione a[i][j] è implementata come *(*(a + i) + j)
  • 77. Passare array multidimensionali a funzioni ¤ Supponiamo di voler scrivere una funzione sum_int_matrix che sommi i valori di un array multidim. di interi int main () { int matrix[3][3] = {{1, 7, 14}, {8, 16, 12}, {27, 32, 5}}; int sum = sum_int_matrix(matrix); std::cout << "the elements sum up to " << sum << std::endl; }
  • 78. Passaggio per indirizzo ¤ IDEA: fare in modo che sum_int_matrix accetti un puntatore alla prima riga ¤ Un puntatore alla prima riga permette di: ¤ Muoversi tra gli elementi della stessa riga ¤ Muoversi tra righe successive int sum_int_matrix(int (*matrix)[3], size_t row_num); Puntatore ad un array di 3 elementi di tipo int, cioè un puntatore ad un riga dell’array multidimensionale
  • 79. Passaggio per indirizzo ¤ Quando si passano array multidim. tutte le dimensioni tranne la prima devono essere note a compile-time ¤ L’accesso ad un array multidim. di tipo T[m][n] avviene mediante un puntatore a tipo T[n] ¤ L’uso del puntatore ci permette di non conoscere m, ma il valore n deve comunque essere noto int sum_int_matrix(int (*matrix)[3], size_t row_num); int sum_int_array(int* array, size_t dim_array); In caso di array nessuna dimensione è nota compile- time Il numero di elementi in ogni riga deve essere noto a compile-time
  • 80. Passaggio per indirizzo ¤ L’implementazione di sum_int_matrix è dunque: ¤ L’operatore [] ci permette di manipolare il puntatore matrix con la stessa sintassi che useremmo per un vero array multidimensionale int sum_int_matrix(int (*matrix)[3], size_t row_num) { int sum = 0; for (size_t i = 0; i < row_num; ++i) for (size_t j = 0; j < 3; ++j) sum += matrix[i][j]; return sum; }
  • 81. Sintassi alternativa ¤ Come per gli array, esiste una sintassi alternativa per acquisire l’indirizzo della prima riga di un array multidim. ¤ I tre seguenti prototipi di sum_int_matrix sono equivalenti: ¤ NOTA: tale equivalenza vale unicamente quando si dichiara una funzione int sum_int_matrix(int (*matrix)[3], size_t row_num); int sum_int_matrix(int matrix[][3], size_t row_num); int sum_int_matrix(int matrix[3][3], size_t row_num);
  • 83. Container ¤ Esempi: Un array è un contenitore di oggetti sequenziali di un singolo tipo dato e di dimensione fissa Un contenitore è un oggetto in grado di memorizzare altri oggetti (detti elementi) Un vector è un contenitore di oggetti sequenziali di un singolo tipo dato e di dimensione variabile
  • 84. Container ¤ Esempi di container: ¤ Array ¤ std::vector ¤ std::map ¤ std::multimap ¤ std::unordered_map ¤ std::set ¤ std::unordered_set ¤ std::multiset ¤ std::list
  • 85. Iteratori ¤ Come suggerito dal nome, gli iteratori sono utilizzati per iterare (scorrere) tra gli elementi di un container ¤ In questo modo: ¤ Il container ha il solo compito di utilizzare una strategia di memorizzazione per preservare gli elementi in memoria ¤ L’iteratore ha il solo compito di fornire uno strumento di accesso agli elementi
  • 86. Iteratori ¤ Ogni iteratore è associato ad un elemento del corrispettivo container 1 7 13 5 9numbers: it_1st_elem int[5] it_3rd_elem
  • 87. Iteratore di inizio e fine ¤ Ogni iteratore è associato ad un elemento del corrispettivo container ¤ In particolare, per ogni container identifichiamo due iteratori speciali: ¤ Un iteratore posizionato in corrispondenza del 1° elemento ¤ Un iteratore in posizione successiva all’ultimo elemento
  • 88. Iteratore di inizio e fine 1 7 13 5 9numbers: begin_iterator int[5] end_iterator
  • 89. Iteratore di inizio e fine ¤ Il C++11/14 fornisce due funzioni per ottenere facilmente entrambi gli iteratori: auto begin_it = std::begin(numbers); auto end_it = std::end(numbers);
  • 90. Iteratore ¤ Si può chiedere ad un iteratore: ¤ di recuperare un elemento ¤ di muoversi da un elemento all’altro
  • 91. Recuperare un elemento ¤ Ogni iteratore è associato ad un elemento del corrispettivo container ¤ Dato un iteratore, è possibile ottenere il valore a lui associato auto begin_it = std::begin(numbers); std::cout << "the first element of numbers is: " << *begin_it << std::endl; Anteponendo l’asterisco otteniamo il valore associato all’iteratore begin_it
  • 92. Muoversi da un elemento all’altro ¤ Possiamo usare l’operazione aritmetica di somma per spostare l’iteratore di una posizione auto it = std::begin(numbers); std::cout << "first element: " << *it << std::endl; ++it; std::cout << "second element: " << *it << std::endl; Sommando +1 al valore dell’iteratore mi sposta alla posizione successiva
  • 93. Muoversi da un elemento all’altro 1 7 13 5 9numbers: it int[5] ++it
  • 94. Muoversi da un elemento all’altro 1 7 13 5 9numbers: it int[5]
  • 95. Iteratori ¤ Un iteratore è una generalizzazione del concetto di puntatore ¤ In particolare, come con i puntatori: ¤ Un iteratore è un oggetto che punta ad un altro oggetto ¤ L’elemento puntato è recuperabile mediante l’operatore * ¤ È possibile muoversi puntare all’elemento successivo mediante operazioni aritmetiche
  • 96. Navigare l’array ¤ Una volta disponibili gli iteratori di inizio e di fine è possibile navigare l’array for (auto it = begin_it; it != end_it; ++it) std::cout << *it << std::endl; 1 7 13 5 9numbers: begin_it int* int[5] end_itit
  • 97. Algoritmi standard ¤ Gli iteratori possono essere utilizzati per compiere una moltitudine di operazioni sui container ¤ Tutti gli algoritmi standard del C++ accettano in ingresso una coppia di iteratori ¤ La coppia delimita la porzione del container su cui si vuole agire ¤ In questo modo ogni algoritmo può essere usato con un qualsiasi container, purchè esponga degli iteratori
  • 98. Algoritmi standard ¤ Esempio: copiare un container ¤ Esempio: sommare i valori in un container ¤ Il codice non sarebbe cambiato anche se numbers fosse stato un vector o un set int other_numbers[5]; std::copy(std::begin(numbers), std::end(numbers), std::begin(other_numbers)); int sum = std::accumulate(std::begin(numbers), std::end(numbers), 0);
  • 100. Bibliografia ¤ S. B. Lippman, J. Lajoie, B. E. Moo, C++ Primer (5th Ed.) ¤ B. Stroustrup, The C++ Programming Language (4th Ed.) ¤ The Gang of Four, Design Patterns - Elements of Reusable Object Oriented Software ¤ HP, Standard Template Library Programmer's Guide https://www.sgi.com/tech/stl/ ¤ Stackoverflow FAQ, “How do I use arrays in C++?” http://stackoverflow.com/questions/4810664/how-do-i-use- arrays-in-c