HOWTO · C++

Dichiarare un array di vettori in C++ STL

Questo articolo introduce come dichiarare un array di vettori in C++

In questa pagina

Questa guida mostra come dichiarare in C++ un numero fisso di vettori oppure un vettore di vettori ridimensionabile. Il contenitore esterno determina quante righe si possono aggiungere; ogni vettore interno std::vector determina quanti valori contiene quella riga. Scegli la prima forma se il numero di righe è fisso, la seconda se la raccolta esterna deve poter aumentare o diminuire di dimensione.

Scegliere tra un array fisso e un vettore di vettori

Un array di vettori ha un numero di righe fissato in fase di compilazione, mentre ogni riga è comunque un vettore che può crescere indipendentemente. Anche il numero di righe di un vettore di vettori può cambiare e ogni riga può avere una lunghezza diversa. Perciò un vettore di vettori non è necessariamente una matrice rettangolare. È utile, per esempio, per rappresentare liste di adiacenza, in cui ogni elemento può avere un numero diverso di vicini.

In entrambe le forme, gli elementi sono vettori, quindi i vettori interni gestiscono la propria memoria. Nessuna delle due dichiarazioni garantisce che tutte le righe contengano lo stesso numero di valori. Se l’algoritmo richiede una struttura rettangolare, inizializza ogni riga con la stessa larghezza e mantieni questa condizione quando modifichi i dati.

Dichiarare un array di vettori con la sintassi degli array in stile C

Se il numero di righe è fisso, dichiara un array il cui tipo di elemento è std::vector<int>, per esempio std::vector<int> rows[3];. L’array contiene tre vettori. All’inizio questi vettori non contengono valori, ma puoi aggiungerne a una riga con rows[0].push_back(10). L’array non può crescere per contenere un quarto vettore: se il numero di righe deve poter cambiare, usa un contenitore esterno ridimensionabile.

Questa sintassi è utile quando il numero di righe fa parte della struttura fissa del programma. La dimensione dell’array è determinata dalla dichiarazione, mentre quella di ciascun vettore può cambiare durante l’esecuzione. Le due dimensioni seguono quindi regole diverse: l’array esterno è fisso e i vettori interni sono ridimensionabili.

Dichiarare un vettore di vettori ridimensionabile

Usa std::vector<std::vector<int>> se il numero di righe deve poter cambiare. Una lista di inizializzazione può creare righe con lunghezze iniziali diverse. In alternativa, std::vector<std::vector<int>> rows(3, std::vector<int>(2, 0)); crea tre righe, ciascuna con due zeri. In questa forma del costruttore, il primo argomento indica il numero di righe; il secondo è un vettore copiato per inizializzare ogni riga.

Puoi aggiungere una nuova riga con rows.push_back({8, 9}) oppure aggiungere un valore a una riga esistente con rows[0].push_back(7). Aumentare o ridurre la dimensione di una riga non ridimensiona automaticamente le altre. Scegli la forma con il costruttore per creare una griglia iniziale regolare; se le lunghezze delle righe variano, usa una lista di inizializzazione oppure costruiscile una alla volta.

Accedere e iterare su un vettore di vettori

Usa rows[row][column] per accedere direttamente a un elemento quando sai che gli indici sono validi. Ogni indice si applica a un vettore diverso: il primo seleziona una riga esterna, il secondo un valore all’interno di quella riga. Poiché le righe possono avere lunghezze diverse, un indice di colonna valido per una riga potrebbe non esserlo per un’altra.

Usa rows.at(row).at(column) per un accesso con controllo dei limiti: at() segnala un accesso fuori intervallo invece di indicizzare silenziosamente oltre i limiti del vettore selezionato. Per visitare tutti i valori senza presupporre che le righe abbiano la stessa lunghezza, usa cicli annidati basati su intervalli. Associa il valore interno per riferimento (int& value) se il ciclo deve modificare gli elementi memorizzati; per la sola lettura, usa una variabile per valore o un riferimento costante. L’esempio completo seguente mostra entrambe le forme di dichiarazione, l’indicizzazione, l’accesso con controllo dei limiti, l’aggiunta di elementi e la modifica dei valori tramite riferimento.

Questo programma completo mostra entrambe le strutture dei contenitori e accede ai loro valori:

Il codice e le etichette o gli output visibili in questa sezione restano in inglese.

#include <iostream>
#include <vector>

int main() {
  std::vector<int> fixed_rows[3] = {{1, 2}, {3}, {4, 5, 6}};
  std::vector<std::vector<int>> rows{{1, 2}, {3}, {4, 5, 6}};

  fixed_rows[0].push_back(7);
  rows.push_back({8, 9});
  rows[1].push_back(7);
  rows.at(0).at(1) = 20;

  std::cout << fixed_rows[0][2] << '\n';
  std::cout << rows.at(0).at(1) << '\n';
  for (auto& row : rows) {
    for (int& value : row) {
      value *= 2;
      std::cout << value << ' ';
    }
    std::cout << '\n';
  }
}