Home

ITA - Appunti Cpp 004 - Vettori

linux debian lmde cpp

Definizione di un array c-style

Un array è una sequenza di elementi dello stesso tipo, conservata in porzioni 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.

Un array ha una dimensione costante che deve essere specificato nella sua dichiarazione o desumibile della sua definizione.

#include <iostream>
#include <iterator>
#include <numeric>

int main{
    // 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};
}

Trasformazione da array a puntatore

Esiste una conversione implicita da lvalue a rvalue di tipo array a rvalue di tipo puntatore: costruisce un puntatore al primo elemento di un array. Questa conversione viene utilizzata ogni volta che gli array appaiono in un contesto in cui non sono previsti array.

#include <iostream>
#include <iterator>
#include <numeric>
 
void g(int (&a)[3])
{
    std::cout << a[0] << '\n';
}
 
void f(int* p)
{
    std::cout << *p << '\n';
}
 
int main()
{
    int a[3] = {1, 2, 3};
    int* p = a;
 
    std::cout << sizeof a << '\n'  // stampa la dimensione dell'array
              << sizeof p << '\n'; // stampa la dimensione del puntatore
 
    // nei contensti in cui sono consentiti solo gli array, l'uso di un puntatore
    // deve essere evitato
    g(a); // ok: la funzione accetta il riferimento a un array 
//  g(p); // errore
 
    for (int n : a)            // ok: gli array possono essere usati nei ranged-for loops
        std::cout << n << ' '; // stampa gli elementi dell'array
//  for (int n : p)            // errore
//      std::cout << n << ' ';
 
    std::iota(std::begin(a), std::end(a), 7); // ok
//  std::iota(std::begin(p), std::end(p), 7); // errore
 
    // dove i puntatori sono accettati, entrambi possono essere usati:
    f(a); // ok
    f(p); // ok
 
    std::cout << *a << '\n' // stampa il primo elemento 
              << *p << '\n' // lo stesso
              << *(a + 1) << ' ' << a[1] << '\n'  // stampa il secondo elemento
              << *(p + 1) << ' ' << p[1] << '\n'; // lo stesso
}

Matrici

Le matrici sono array di array…

// array di 2 arrays composti da 3 int l'uno
int a[2][3] = { {1, 2, 3},  // può essere vista come una matrice 2 × 3 
               {4, 5, 6} }; // con una disposione in fila 

int a[2];            // array di 2 int
int* p1 = a;         // trasformazione a puntatore del primo elemento
 
int b[2][3];         // matrice di 2 x 3 int
// int** p2 = b;     // errore: b non è trasformabile in int**
int (*p2)[3] = b;    // b decade al puntatore all'array dei primi 3 lementi di b
 
int c[2][3][4];      // array di 2 arrays di 3 arrays di 4 int
// int*** p3 = c;    // errore: c non è trasformabile in int***
int (*p3)[3][4] = c; // c decade a un puntatore de primo piano 3 × 4-elementi di c

NB: quando una trasformazione array-to-pointer è applicata a una matrice, viene fatto solo una volta

Uso di un std::array

std::array è un container che incapsula gli arrays, la semantica è uguale a quella degli array, ad eccezione che non decadono a T* automaticamente. Questa struttura combina le prestazioni e l’accessibilità di un array c-style con i benefici di un container standard, come la dimensione nota, supporto all’allassegnazione, iteratori ecc…

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <string>
 
int main()
{
    // La definizione con dati aggregati
    std::array<int, 3> a1{ {1, 2, 3} }; // Prima del C++11 erano necessarie le doppie parentesi
                                      // dopo la revisione CWG 1270, dal C++14 in avanti non sono 
                                      // più necessarie
 
    // operazioni relative ai container
    std::sort(a1.begin(), a1.end());
    std::ranges::reverse_copy(a2, std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
 
    // supporto a cicli
    std::array<std::string, 2> a3{"E", "\u018E"};
    for (const auto& s : a3)
        std::cout << s << ' ';
    std::cout << '\n';
}

Definizione di una vettore

I vettori sono implementati in modi diversi:

  1. std::vector è un contenitore che incapsula array a dimensione dinamica.
  2. std::pmr::vector è un template alias che usa gli allocatori polimorfi.
#include <iostream>
#include <vector>
 
int main()
{
    // Creare un vettore che contiene interi
    std::vector<int> v = {8, 4, 5, 9};
 
    // aggiungi due elementi
    v.push_back(6);
    v.push_back(9);
 
    // sovrascrivi l'elemento al secondo posto
    v[2] = -1;
 
    // Stampa il vettore
    for (int n : v)
        std::cout << n << ' ';
    std::cout << '\n';
}

Riferimenti