Array e matrici
Array o vettore
Un array, o vettore, è un insieme di elementi dello stesso tipo memorizzati in posizioni di memoria contigue.
Un array può avere elementi di qualsiasi tipo base (int, char, float, double, bool). In questo esempio la variabile foo è un array di 5 elementi di tipo intero.
Gli elementi dell’array sono identificati tramite un nome (la variabile array) ed un indice (la posizione dell’elemento nell’array). Gli array hanno una dimensione fissa, definita quando vengono creati.
Gli array sono memorizzati nella memoria del programma (o meglio, del processo in esecuzione) in uno spazio contiguo. Questo permette di avere prestazioni eccellenti ma ha come limite proprio il fatto che non sono ridimensionabili.
Un array si dichiara nel seguente modo:
int foo[5];
Bisogna quindi dare sempre una dimensione, usando le parentesi quadre. E’ possibile anche inizializzare un array con dei valori, ma solo contestualmente alla definizione:
int foo[5] = { 34, 12, 7, 3, 18}; -> crea un array e lo popola con 5 elementi
int foo[5] = { 34, 12, 90} -> crea un array e lo popola con 3 elementi (gli altri restano a 0)
int foo[5] = { } -> crea un array con tutti gli elementi a 0
Agli elementi si accede tramite indice:
foo[3] = 2;
cout << foo[2];
c = foo[x+1];
Nell’ultima istruzione il valore della variabile memorizzata può essere indice di un array.
Qui un esempio di utilizzo.
#include <iostream>
using namespace std;
int main() {
int a[5] = {1,2,3,4,5};
for (int i=0; i<5; i++) {
cout << a[i] << " ";
}
return 0;
}
Notare che gli indici partono sempre da 0. Questo significa che in un array di n elementi, gli indici andranno da 0 a n-1.
Come detto sopra la dimensione dichiarata è fissa, ma in C/C++ non esiste un controllo per andare oltre i limiti di un array. Quindi nulla vieta di scrivere una istruzione in C++ che legge o scrive oltre i limiti di un array, e quindi accedere ad aree di memoria non allocate o anche allocate ad altro. E’ una caratteristica del linguaggio di cui bisogna sempre fare attenzione.
Ad esempio:
int foo[5] = { 34, 12, 7, 3, 18};
foo[7] = 21; // l'istruzione non da errore
Il fatto che l’istruzione non dia errore non significa che sia un comportamento corretto, il rischio è quello di andare a scrivere in zone di memoria dove magari sono presenti anche altre variabili. Vedremo questo in dettaglio nella gestione della memoria.
Siccome un array non è una variabile base non è possibile copiare un array con una semplice assegnazione ma occorre copiare ogni singolo valore, ad esempio con un ciclo for. Qui un esempio:
#include <iostream>
using namespace std;
int main() {
int a[5] = {1,2,3,4,5};
int b[5];
for (int i=0; i<5; i++) {
b[i] = a[i];
}
return 0;
}
L’uso pratico degli array consiste nel memorizzare liste di valori dello stesso tipo, con questo sistema è quindi possibile memorizzare sequenze a fini di calcolo, di statistica, di memorizzazione ecc.
Matrici
Le matrici sono array multidimensionali. Qui un esempio a 2 dimensioni (righe e colonne):
int matrix[2][3]; // 2 righe e 3 colonne
Si possono anche assegnare valori ricordandosi che vengono inseriti riga per riga:
int matrix[2][3] = { 1, 2, 3, 4, 5, 6 };
for (int riga = 0; riga < 2; riga++) {
for (int colonna = 0; colonna < 3; colonna++) {
cout << matrix[riga][colonna];
}
cout << endl;
}
Questa produrrà:
1 2 3
4 5 6
Le matrici possono anche essere con 3 o dimensioni o più:
int cube[3][3][3];
int multiD[2][3][5][7];
Copia di array e matrici
Non è possibile copiare il contenuto di un array in un altro come succede con una variabile. Proviamo a capire cosa succede con un esempio:
int array1[3] = {1,2,3};
int array2[3]:
array2 = array1;
Con questo esempio quello che succede è che l’array2 diventa un alias dell’array1, in altre parole stiamo dicendo che l’array2 coincide con l’array1. Si dice che array2 è una shadow copy (“copia ombra”) di array1. Pertanto se scriviamo queste istruzioni:
array2[1] = 0;
cout << array1[1]; // stampa 0, perché i due array coincidono
Se invece vogliamo creare proprio una copia di un array dobbiamo copiare uno a uno i valori dell’array stesso.
int array1[3] = {1,2,3};
int array2[3]:
for (int i=0; i<3; i++) {
array2[i] = array1[i];
}
In questo caso abbiamo compiuto una deep copy (“copia profonda”) dell’array1.