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

PPTX
Functions, classes & objects in c++
PPT
C# basics
PPTX
Standard Template Library
PDF
Standard template library
PPTX
Pointers in C
PPTX
Kotlin Collections
PDF
Lecture 4 variables data types and operators
PPTX
Pointer to function 1
Functions, classes & objects in c++
C# basics
Standard Template Library
Standard template library
Pointers in C
Kotlin Collections
Lecture 4 variables data types and operators
Pointer to function 1

What's hot (20)

PPT
Exception handling
PPTX
Arrays & Strings
PPTX
Classes and objects1
PPTX
Pointers in c - Mohammad Salman
PPTX
Standard template library
PPTX
Clean Code
PDF
Constructor and Destructor
PDF
Constants, Variables and Data Types in Java
PPT
Basics of pointer, pointer expressions, pointer to pointer and pointer in fun...
PDF
List , tuples, dictionaries and regular expressions in python
PPTX
Data Types In C
PPT
One dimensional 2
PPTX
C programming
PDF
An Introduction to Programming in Java: Arrays
PPTX
Pointers and Structures.pptx
PDF
PPTX
Unary operator overloading
DOCX
Structure and Typedef
PPTX
Arrays In C++
PPTX
Pointer to array and structure
Exception handling
Arrays & Strings
Classes and objects1
Pointers in c - Mohammad Salman
Standard template library
Clean Code
Constructor and Destructor
Constants, Variables and Data Types in Java
Basics of pointer, pointer expressions, pointer to pointer and pointer in fun...
List , tuples, dictionaries and regular expressions in python
Data Types In C
One dimensional 2
C programming
An Introduction to Programming in Java: Arrays
Pointers and Structures.pptx
Unary operator overloading
Structure and Typedef
Arrays In C++
Pointer to array and structure
Ad

Viewers also liked (12)

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

Similar to Array in C++ (20)

PDF
Lezione 13 (2 aprile 2012)
PDF
Lezione 13 (2 aprile 2012)
PPT
06 1 array_stringhe_typedef
PDF
Lezione 12 (28 marzo 2012) puntatori vettori
PPT
6 Vettori E Matrici
PPSX
PPTX
06 2 vector_matrici
PPT
13 Puntatori E Memoria Dinamica
PDF
Puntatori e Riferimenti
PDF
10 - Programmazione: Tipi di dato strutturati
PDF
Esercitazione 3 (14 marzo 2012)
PDF
17 - Programmazione: Introduzione alle liste
PPTX
06 3 struct
PDF
12 - Programmazione: Array dinamici e puntatori
PPTX
Puntatori in C++
PPT
Riepilogo Java C/C++
PPT
Corso c++
ODP
PDF
Eserc v del 26 marzo 2012
PPT
Java lezione 2
Lezione 13 (2 aprile 2012)
Lezione 13 (2 aprile 2012)
06 1 array_stringhe_typedef
Lezione 12 (28 marzo 2012) puntatori vettori
6 Vettori E Matrici
06 2 vector_matrici
13 Puntatori E Memoria Dinamica
Puntatori e Riferimenti
10 - Programmazione: Tipi di dato strutturati
Esercitazione 3 (14 marzo 2012)
17 - Programmazione: Introduzione alle liste
06 3 struct
12 - Programmazione: Array dinamici e puntatori
Puntatori in C++
Riepilogo Java C/C++
Corso c++
Eserc v del 26 marzo 2012
Java lezione 2

More from Ilio Catallo (20)

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

Recently uploaded (9)

PPTX
Copia di PROGETTO VIOLENZA sulle donne PCTO
PDF
GIÁO ÁN CHÍNH KHÓA TIẾNG ANH 9 - CẢ NĂM - THEO CÔNG VĂN 5512 (2 CỘT) NĂM HỌC ...
PPTX
SLIDE-DE-CURSOS-OssssFICIAL-DA-EGEPI-.pptx
PDF
Mazzoni-Reggi-2012-Effetto-Lucifero-Su-Wikipedia.pdf
PDF
GIÁO ÁN KẾ HOẠCH BÀI DẠY CHÍNH KHÓA TIẾNG ANH 9 - CẢ NĂM - THEO CÔNG VĂN 5512...
PDF
BÀI TẬP TEST BỔ TRỢ THEO TỪNG UNIT - TIẾNG ANH 10 EXPLORE NEW WORLDS - CẢ NĂM...
PDF
16 CHUYÊN ĐỀ BÀI TẬP ÔN THI TUYỂN SINH VÀO 10 - MÔN TIẾNG ANH - THEO FORM ĐỀ ...
PDF
BÀI TẬP TEST BỔ TRỢ THEO TỪNG UNIT - TIẾNG ANH 10 FRIENDS GLOBAL - CẢ NĂM (24...
PDF
CHUYÊN ĐỀ BỔ TRỢ NGỮ ÂM, TỪ VỰNG NÂNG CAO - TIẾNG ANH 9 VÀ ÔN THI VÀO LỚP 10 ...
Copia di PROGETTO VIOLENZA sulle donne PCTO
GIÁO ÁN CHÍNH KHÓA TIẾNG ANH 9 - CẢ NĂM - THEO CÔNG VĂN 5512 (2 CỘT) NĂM HỌC ...
SLIDE-DE-CURSOS-OssssFICIAL-DA-EGEPI-.pptx
Mazzoni-Reggi-2012-Effetto-Lucifero-Su-Wikipedia.pdf
GIÁO ÁN KẾ HOẠCH BÀI DẠY CHÍNH KHÓA TIẾNG ANH 9 - CẢ NĂM - THEO CÔNG VĂN 5512...
BÀI TẬP TEST BỔ TRỢ THEO TỪNG UNIT - TIẾNG ANH 10 EXPLORE NEW WORLDS - CẢ NĂM...
16 CHUYÊN ĐỀ BÀI TẬP ÔN THI TUYỂN SINH VÀO 10 - MÔN TIẾNG ANH - THEO FORM ĐỀ ...
BÀI TẬP TEST BỔ TRỢ THEO TỪNG UNIT - TIẾNG ANH 10 FRIENDS GLOBAL - CẢ NĂM (24...
CHUYÊN ĐỀ BỔ TRỢ NGỮ ÂM, TỪ VỰNG NÂNG CAO - TIẾNG ANH 9 VÀ ÔN THI VÀO LỚP 10 ...

Array in C++

  • 1. Array Ilio Catallo – info@iliocatallo.it
  • 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