Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 65 di 93
  • livello avanzato
Indice lezioni

Array multidimensionali

In C++ come in altri linguaggi di programmazione, gli array possono avere più dimensioni: ecco come creare e gestire "matrici" multidimensionali.
In C++ come in altri linguaggi di programmazione, gli array possono avere più dimensioni: ecco come creare e gestire "matrici" multidimensionali.
Link copiato negli appunti

Gli array in C++ possono variare oltre che per numero di elementi, anche per numero di dimensioni.

Il listato seguente contiene la dichiarazione di un array avente due dimensioni:

#include <iostream>
int main()
{
int myArray2D [2][4] = { 1, 2, 3, 4, 5, 6, 7, 8 };
for (int i=0; i<2; i++)
{
std::cout << "row [" << i << "] : ";
for (int j=0; j<4; j++)
{
std::cout << myArray2D[i][j] << " ";
}
std::cout << "\n";
}
return 0;
}

Osservando la dichiarazione della variabile myArray2D, si evince che il numero di dimensioni è dato dal numero di coppie di parentesi quadre che seguono il nome, mentre il numero di elementi relativo ad ogni dimensione è espresso tra le suddette parentesi (in questo caso 2 e 4 rispettivamente).

Anche se, indipendentemente dal numero di dimensioni, gli elementi di un array sono sempre allocati in una porzione di memoria composta da locazioni contigue, nel caso di array bidimensionali, come in questo esempio, possiamo immaginare una rappresentazione in forma matriciale.

Nelle istruzioni successive alla sua definizione, l'array viene scandito mediante due cicli annidati che stampano a schermo le due righe composte da quattro elementi ciascuna. Si noti che per accedere in lettura o scrittura ad ogni elemento della matrice è necessario indicare ordinatamente i due indici, rispettivamente per righe e colonne, tra parentesi quadre. Questa stessa sintassi si estende al caso di array con dimensioni superiori.

Possiamo sfruttare la rappresentazione su righe e colonne anche per rendere più leggibile la sua dichiarazione usando una forma alternativa, ma del tutto equivalente alla precedente, come mostrato nel frammento seguente:

int myArray2D [2][4] = {
{1, 2, 3, 4} ,
{5, 6, 7, 8}
};
int myArray3D [2][2][2] = {
{
{1, 2} ,
{3, 4}
} ,
{ {5, 6} ,
{7, 8}
}
};

Si noti che in questo caso le righe sono raggruppate tra parentesi graffe e separate da virgole. Eventuali errori nella definizione, ad esempio, una riga in più o un elemento in più in una riga, sono segnalati dal compilatore.

Questa modalità si estende ovviamente al caso di più dimensioni, ad esempio la variabile myArray3D. L'uso di andate a capo e tabulazioni è del tutto trasparente per il compilatore e può essere applicato per incrementare la leggibilità del codice, se necessario.

Dichiarazione dinamica di array multidimensionali

Come visto in precedenza per gli array monodimensionali, è possibile allocare dinamicamente anche array multidimensionali. A questo scopo si fa uso di puntatori a puntatori per allocare dinamicamente le varie porzioni dell'array. Il listato seguente mostra come viene istanziato un array bidimensionale in maniera dinamica:

#include <iostream>
int main()
{
int rows = 2;
int cols = 4;
// allocazione di un puntatore per ogni riga
int **myDynamicArray2D = new int*[rows];
// allocazione dell'array che contiene ogni riga
for (int i=0; i<rows; i++)
{
myDynamicArray2D[i] = new int[cols];
}
// definizione degli elementi
for (int i=0; i<rows; i++)
{
for (int j=0; j<cols; j++)
{
myDynamicArray2D[i][j] = (i * cols) + j + 1;
}
}
// stampa delle righe
for (int i=0; i<rows; i++)
{
std::cout << "row [" << i << "] : ";
for (int j=0; j<cols; j++)
{
std::cout << myDynamicArray2D[i][j] << " ";
}
std::cout << "\n";
}
// deallocazione delle singole righe
for (int i=0; i<rows; i++)
{
delete[] myDynamicArray2D[i];
}
// deallocazione dei puntatori alle righe
delete[] myDynamicArray2D;
return 0;
}

L'allocazione dinamica di un array si articola in più fasi, una per ogni dimensione aggiuntiva oltre la prima. Nel caso di un array bidimensionale, per rendere semplice l'indicizzazione delle righe possiamo, in primo luogo, allocare un array i cui elementi sono tutti puntatori. Il secondo passo consiste nell'allocare per ognuno di questi puntatori uno spazio di memoria sufficiente a contenere tutti gli elementi di ogni riga.

Solo dopo che l'area di memoria destinata ad ospitare gli elementi del nostro array è stata correttamente riservata, è possibile procedere all'attribuzione di un valore ad ogni elemento, in questo caso i numeri progressivi da 1 a 8.

Infine in modo del tutto equivalente al caso precedente è possibile procedere alla stampa riga per riga del nostro array multidimensionale.

La deallocazione avviene in maniera inversa rispetto la fase di allocazione; prima si deallocano gli array che contengono gli elementi di ogni riga, e poi si dealloca l'array che ne contiene i puntatori.

Anche questa modalità si estende al caso di array con dimensione superiore a due, aggiungendo un ulteriore livello di indirezione (puntatore a puntatore a puntatore a ... e così via) e avendo cura di applicare opportunamente allocazione e deallocazione per ogni dimensione aggiunta.

Differenze tra array statici e dinamici

Sotto molti aspetti, gli array statici (nel senso che la loro dimensione è determinata a tempo di compilazione, senza riferimenti al qualificatore static) e quelli allocati dinamicamente, cioè a tempo di esecuzione, sono perfettamente interscambiabili in termini di funzionalità. Tuttavia essi sono fondamentalmente due costrutti distinti che hanno anche notevoli differenze tra di loro:

  • il tipo: un array statico è un'entità caratterizzata da un proprio tipo che è strettamente correlato alla sua cardinalità, mentre un array allocato dinamicamente non ha questa proprietà
  • il layout: un array statico è necessariamente costituito da locazioni di memoria contigue, anche nel caso multidimensionale. Nulla vieta quindi di accedere agli elementi delle righe e colonne utilizzando un indice lineare opportunamente calcolato. Un'array allocato dinamicamente invece è sparso in più porzioni di memoria non necessariamente contigue
  • variabilità del numero di elementi: la dimensione di un array dinamico può variare, per effetto di deallocazioni e nuove allocazioni di memoria. La dimensione di un array statico è invece immutabile, del resto essa è parte integrante della sua definizione di tipo

La differenza che riguarda il tipo è importante, come vedremo meglio nel seguito, quando si usano gli array come argomenti di metodi e funzioni, mentre, per grandi moli di dati, la diversa disposizione in memoria può avere un impatto in termini di efficienza.

Ti consigliamo anche