Un array è una sequenza di elementi dello stesso tipo, immagazzinata in locazioni di memoria contigue. Ad un array è associato un identificativo che può essere indicizzato numericamente per accedere ai singoli elementi. La prima locazione dell'array è associata all'indice 0, e coincide con l'indirizzo dell'indentificativo stesso.
A prescindere dalle sue peculiarità, un array è una variabile, ed in quanto tale valgono le stesse regole per la dichiarazione e la definizione dei suoi valori, l'uso di qualificatori e l'ambito di visibilità.
La dimensione di un array è un valore costante che deve essere specificato nella sua dichiarazione o desumibile della sua definizione. L'operatore []
è usato a tale scopo, come illustrato nel frammento C++ seguente.
// dichiarazione senza inizializzazione, con dimensione pari a 5
int myArray[5];
// dichiarazione e definizione, la dimensione è desunta dal compilatore
int myArray[] {2, 4, 6, 8, 10};
Ad un array definito in uno dei modi illustrati in precedenza corrisponde una rappresentazione in memoria come quella riportata in figura:
Ogni elemento ha una dimensione in byte pari a quella del tipo nominale dell'array, in questo caso int
, e l'indice ad esso associato è un numero progressivo che identifica la sua posizione assoluta, ed è quindi indipendentemente dalla dimensione degli elementi in byte.
L'operatore []
viene usato anche per accedere agli elementi di un array in base al loro indice come mostrato di seguito per alterare o leggere il valore contenuto:
int myArray[] {2, 4, 6, 8, 10};
// scrittura
myArray[3] = 123; // {2, 4, 6, 123, 10};
// lettura
int a = myArray[2]; // a = 6;
Scansione di un array
Un array può essere facilmente scandito mediante uno dei costrutti iterativi del linguaggio, ad esempio il ciclo for, come mostrato nel listato seguente:
#include <iostream>
int main()
{
int myArray[] {2, 4, 6, 8, 10};
for (int i=0; i<5; i++)
{
std::cout << "index: " << i << " - value: " << myArray[i] << "\n";
}
return 0;
}
Che produce il seguente output:
index: 0 - value: 2
index: 1 - value: 4
index: 2 - value: 6
index: 3 - value: 8
index: 4 - value: 10
L'espressione di inizializzazione della variabile usata come indice, i in questo caso, e la condizione di uscita dal ciclo devono entrambe tenere conto dei limiti dell'array cioè 0 e dimensione - 1, per evitare di commettere violazioni di accesso alla memoria.
Allocazione dinamica
Negli esempi proposti finora, si è fatto riferimento ad allocazioni sul segmento di memoria dello stack. Poichè per loro natura, gli array si prestano alla manipolazioni di molteplici istanze di uno stesso tipo, compresi anche i tipi complessi definiti dall'utente, i limiti posti sulla dimensione dello stack potrebbeno rappresentare un problema per gestire quantità di dati più significative.
In questi casi è possibile allocare gli array nello heap in modo dinamico usando un puntatore come identificativo e la parola chiave new
, come illustrato nel segmento seguente:
int* myArray = new int[500];
if (myArray)
{
// do stuff
delete[] myArray;
}
In questo caso, la dimensione di un array allocato dinamicamente non deve necessariamente essere il risultato di un'espressione costante a tempo di compilazione.
Se si verifica un problema in fase di allocazione della memoria, ad esempio se la dimensione dell'array è eccessiva, il puntatore sarà nullo, pertanto è sempre opportuno verificare il buon esito dell'operazione prima di accedere agli elementi dell'array.
Analogomente al caso di variabili oridinarie, la deallocazione deve essere gestita dal programmatore mediante l'operatore delete[]
.
L'uso delle parentesi quadre in questo caso è fondamentale per la corretta deallocazione dell'intera area di memoria occupata dall'array. Si noti che non è necessario specificare il numero di elementi quando di usa l'operatore delete[]
, poichè essa è solitamente parte dei metadati che definiscono l'identificativo dell'array stesso ed è tipicamente immagazzinata in una porzione di memoria in testa alla prima locazione.