Indice del libro

Un array in C++ è un insieme di elementi omogenei tra loro. I dati vengono raggruppati e organizzati secondo uno schema ben definito prende il nome di struttura dati. L'array è una struttura dati che contiene dati dello stesso tipo e dove gli elementi si distinguono uno dall’altro attraverso un indice.

Un array può essere costruito sia a tempo di compilazione, sia a tempo di esecuzione. Nel primo caso la dimensione dell'array dovrà essere nota durante la compilazione, mentre nel secondo caso la dimensione può essere stabilita in fase di esecuzione del programma.

Array Monodimensionali

modifica

Per costruire un array allocato nello stack si deve operare così:

 int mioarray[10];

In questo caso la variabile mioarray ha un raggio d'azione statico e la sua deallocazione in memoria avviene semplicemente quando l'identificatore mioarray va fuori ambito (ad esempio, dopo un ciclo).

Per costruire un array allocato nello heap si deve operare così:

 int *mioarray = new int[n];

La dimensione n è nota solo a tempo di esecuzione, perciò l'intero array sarà allocato nella zona heap. L'unico modo per dereferenziare l'array è mediante il puntatore mioarray. La deallocazione questa volta non è così banale come al caso precedente, poiché essa deve essere effettuata esplicitamente mediante l'operatore delete in questa maniera:

 delete[] mioarray;

Bisogna stare molto attenti perché se il puntatore mioarray va fuori ambito, non esisterà più il modo per effettuare la deallocazione dell'array, e se venisse eseguita l'istruzione appena citata, avverrà un crash al programma (segmentation fault).

L'accesso agli elementi dell'array è semplice, e lo si fa attraverso l'operatore estrazione []:

// stampa del primo elemento
cout << mioarray[0] << endl;

// modifica del primo elemento
mioarray[0] = 0;

Questa sintassi si può usare in tutti e due i casi di allocazione dell'array.

Array Multidimensionali - Matrici

modifica

Creare una matrice non differisce di molto rispetto alla creazione di un array.

Per costruire una matrice quadrata nxn nella memoria stack, si deve operare così:

 int miamatrice[10][10];

Per costruire l'analoga matrice quadrata nxn nella memoria heap, si deve operare così:

// creazione di un array di puntatori
int **miamatrice = new int*[n];
for (int i = 0; i < n; i++)
    miamatrice[i] = new int[n];

Per accedere agli elementi di una matrice, basta [][]:

// stampa l'elemento della prima riga e prima colonna
cout << miamatrice[0][0] << endl;

Realizzare una matrice dinamica in questa maniera può essere un po' pericoloso. Anche se stilisticamente la matrice sembra ben creata, in realtà c'è un problema di fondo. Infatti il C++ (come il C) memorizza gli elementi per riga, e quando viene creata una matrice mediante allocazione statica, la matrice occupa nxn posizioni consecutive. Questo vuol dire che è possibile scorrere l'intera matrice mediante un solo ciclo for, usando l'aritmetica dei puntatori se la matrice viene creata staticamente.

miamatrice non è altro che l'indirizzo del primo elemento, cioè miamatrice = &miamatrice[0][0]. Per scorrere gli elementi mediante un solo ciclo for è necessario fare così:

// si poteva fare anche: primo = miamatrice;
int *primo = &miamatrice[0][0];
for (int i = 0; i < 100; i++)
    cout << (*primo++) << endl;

Questo modo di operare funziona con delle matrici allocate nella memoria stack, ma in generale non vale per quelle allocate nella memoria heap.

Per avere un qualcosa di funzionante, si deve per forza ricorrere a dei trucchetti perdendo però un po' di memoria. Il primo passo è la creazione di un array esteso che simuli la matrice: se la matrice è nxn (n righe e n colonne) dovrà essere creato un array monodimensionale di lunghezza nxn. In questo caso l'aritmetica dei puntatori sarà salvaguardata, ma l'accesso alla matrice non sarà agevole, dato che non ci si potrà accedere specificando la riga e colonna semplicemente.

Per eliminare questo inconveniente, si può usare un array di puntatori ausiliario in modo attaccarlo all'array esteso appena creato. Il codice per far questo è:

int *miamatriceestesa = new int[n*n];

// array di puntatori da agganciare alle righe
int **miamatrice = new int*[n];
for (int i = 0; i < n; i++)
    miamatrice[i] = &miamatriceestesa[n*i];

// riempimento matrice

// si accede male alla matrice, senza specificare la riga e colonna non è facile
int *primo = miamatriceestesa;
for (int i = 0; i < n*n; i++)
    cout << *primo++ << endl;

cout << endl;

// si accede alla matrice in maniera "naturale"
for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
        cout << miamatrice[i][j] << endl;