Array in C++

869 views

Published on

Introduzione agli Array in C++. Argomenti trattati: decadimento a puntatore di un array; conseguenze del meccanismo di decadimento sul passaggio di array a funzioni; array multidimensionali e il concetto di puntatore ad array; come passare array multidimensionali a funzioni; gli iteratori come generalizzazione di un puntatore ad elemento di un array ed una breve scorsa di come usare gli iteratori con gli algoritmi standard (e.g., std::copy) del C++.

Published in: Education
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
869
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
1
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Array in C++

  1. 1. Array Ilio Catallo – info@iliocatallo.it
  2. 2. Outline ¤ Introduzione agli array ¤ Array e puntatori ¤ Array e funzioni ¤ Array multidimensionali ¤ Array e iteratori
  3. 3. Introduzione agli array
  4. 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. 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. 6. Assegnamento ed inizializzazione ¤ Cosa è possibile fare: ¤ Inizializzare un array con una lista di inizializzazione int numbers[] = {1, 7, 13}; // ok, initialization list
  7. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  22. 22. Array e puntatori
  23. 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. 24. Puntatore al primo elemento 1 7 13 5 9numbers: int[5] &numbers[0]first_elem_ptr: int*
  25. 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. 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. 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. 28. Decadimento a puntatore ¤ Questo fenomeno prende il nome di array-to-pointer decay int* first_element_ptr = numbers;
  29. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  42. 42. Array e funzioni
  43. 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. 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. 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. 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. 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. 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. 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. 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);
  51. 51. Array multidimensionali
  52. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 68. Puntatore ad array 1 7 13 5 9 int[5] &numbersnumbers_ptr: int(*)[5] numbers:
  69. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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);
  82. 82. Array e iteratori
  83. 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. 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. 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. 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. 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. 88. Iteratore di inizio e fine 1 7 13 5 9numbers: begin_iterator int[5] end_iterator
  89. 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. 90. Iteratore ¤ Si può chiedere ad un iteratore: ¤ di recuperare un elemento ¤ di muoversi da un elemento all’altro
  91. 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. 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. 93. Muoversi da un elemento all’altro 1 7 13 5 9numbers: it int[5] ++it
  94. 94. Muoversi da un elemento all’altro 1 7 13 5 9numbers: it int[5]
  95. 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. 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. 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. 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);
  99. 99. Bibliografia
  100. 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

×