Gli array in C++ (CAP 3, parte III) - INFN

Indice
Gli array in C++ (CAP 3, parte III)
• Gli array come tipi composti del C++:
Alberto Garfagnini e Marco Mazzocco
• gli array statici (inizializzazione e accesso)
Università degli studi di Padova
A.A. 2014/2015
• puntatori e array
• le funzioni di libreria begin e end()
• gli array dinamici (operatori new e delete)
• il contenitore array della Libreria Standard del C++
Gli Array in C++
2 struttura dati simile al tipo vector della libreria standard del C++:
3 permette di immagazzinare più di un elemento dello stesso tipo
3 e di accedere ad un singolo elemento dell’array specificando la sua posizione
a differenza dei vector
7 hanno una dimensione fissata (i.e. numero di elementi)
7 non è possibile aggiungere o eliminare elementi durante l’esecuzione del
programma
numero di elementi
TypeName arrayName[arraySize];
nome dell’array
Esempio
int months[12];
string text[128];
• Creo un array con 4 elementi:
3 primo elemento seasons[0]
...
3 ultimo elemento seasons[3]
int seasons[4];
[0]
[1]
[2]
[3]
TypeName arrayName[arraySize]
• arraySize può essere:
Sintassi di dichiarazione di un array
Tipo di dato
La creazione di array statici
// array di tipo int con 12 elementi
// array con 128 stringhe
una costante intera
una espressione costante
const int size = 4;
double wine[size];
double wine[8*32+size];
NON è lecita una variabile il cui valore cambia run-time
int dim = 3;
double boxes[dim];
Inizializzazione degli array
3 Gli elementi di un array non sono automaticamente inizializzati
3 esistono svariati modi per inizializzarli :
const unsigned size = 3;
int a[size] = {0, 1, 3};
// La dimensione e’ costante
// a[0] = 0, a[1] = 1, a[2] = 3
L’accesso agli elementi di un array
• Come per le classi string e vector, per accedere agli elementi di
un array possiamo usare:
• un ciclo range for
• l’operatore []
• la variabile indice in un array è di tipo size_t, un tipo unsigned
int a2[] = {0, 1, 3};
int a3[5] = {0, 1, 3};
int a4[2] = 0, 1, 3;
int a5[];
// Un array di dimensione 3
// equivalente a
// a3[] = {0, 1, 3, 0, 0}
// ERRORE: troppi inizializzatori
// ERRORE: dimensione sconosciuta
grande a sufficienza per indirizzare un qualsiasi oggetto in memoria
constexpr size_t size = 5;
double a[size] = {2.2, 3.3, 5.5, 3.8};
for (auto & value : a)
value += offset;
// R/W access
7 ATTENZIONE: No COPY or ASSIGNMENT
int b[] = a;
int c[size];
c = a;
// ERRORE: non possibile inizializzare
// un array con un altro
// ERRORE: non possibile assegnare
// un array con un altro
double sum = 0.0;
for (auto value : a) // READ only access
sum += value;
double mean = sum/size;
for (size_t i = 0; i<size; i++) // R/W access
a[i] *= -1.0;
Puntatori e array
Le funzioni di libreria begin e end
• Tutte le volte che usiamo l’operatore address-of & di fronte ad un oggetto,
• Gli array standard del C++ non permettono un controllo sulla validità
otteniamo un puntatore all’oggetto
• Gli elementi di un array sono oggetti : con l’operatore subscript [] si ottiene
l’oggetto alla locazione indicata dall’indice
const int size = 3;
string num[size] = {"uno", "due", "tre"};
string *ps = & num[0]; //
ps = num;
//
//
//
punta al primo elemento
equivalente, il nome di un array
e’ un puntatore costante al primo
elemento dell’array
3 i puntatori sono iteratori
string *first = num;
// punta al primo elemento
string *last = num + size - 1; // punta all’ultimo elemento
while (first != last) {
cout << *first << endl;
++first;
}
cout << *last << endl; // stampiamo anche l’ultimo
dell’indice dell’elemento al quale si accede
• Il C++ fornisce due funzioni begin e end che forniscono le stesse
funzionalità degli equivalenti membri dei contenitori (per es string e
vector)
int ia[] {0,1,2,3,4,5,6,7,8,9};
int *first = begin(ia); // punta al primo elemento
int *last = end(ia);
// punta all’elemento
// successivo all’ultimo
while (first != last) {
cout << *first << endl;
++first;
}
• Un puntatore "one-past" the end di un array si comporta come un
iteratore ritoranto dal metodo end() di un vector
Gli array dinamici (CAP 12, pag. 476)
Il contenitore array della Libreria Standard del C++
3 Gli array sono contenitori statici : è necessario conoscere la dimensione
dell’array a compile-time e non è possibile aggiungere o togliere elementi
run-time
3 Il contenitore generico array<class T, size_t N>, definito nel file
header <array>, permette di creare un numero prefissato di elementi,
grazie al parametro N
3 gli operatori new/delete permettono di allocare/liberare memoria per
immagazzinare oggetti run-time
3 completamente compatibile, a livello binario, con gli array standard del C :
3 possiamo utilizzarli per creare array dinamici
3 fornisce accesso casuale agli elementi con l’operatore []
3 rispetta il vincolo di contiguità di memoria degli elementi a[i]
array<double, 12> periodo;
TypeName * nomePuntatore = new TypeName[arraySize]
// array di 12 double
è equivalente a
double periodo[12];
double * pd = new double;
int * pia = new int[10];
// crea spazio per un double
// crea un array con 10 int
compile-time e run-time
• è possibile interrogare un array, sia compile-time che run-time per
// elimina il double
// distrugge tutto l’array
ritornare la dimensione dell’array (metodo constexpr size())
Esempio: utilizzo del contenitore array
#include <array>
int main() {
array<int, 4> a1 = {1, 2, 3, 4};
array<int, 4> a2;
// Scambiamo gli array
a2.swap(a1);
a1.fill(-1);
// Controlliamo la contiguita’ degli elementi
for (decltype(a2.size()) i=0; i<a2.size(); i++) {
cout << i << ". ";
cout << a2[i] << " == " << a2.data()[i] << " | ";
cout << &a2[i] << " == " << (a2.data()+i) << endl;
}
}
cout << "a1 = { ";
for (auto e: a1) cout << e << ", ";
cout << " }" << endl;
// Accesso non-sicuro con []
int unsafe = a2[10];
cout << "unsafe: " << unsafe << endl;
// Accesso sicuro con at()
try {
int safe = a2.at(10);
} catch (out_of_range &e) {
cout << "Out Of Range access!" << endl;
}
Esercizio
• Scrivere tre progrmmi che acquisiscano delle misure dallo standard
input e calcolino il valor medio usando:
I ) il contenitore della classe vector per immagazzinare le misure
II ) il contenitore della classe array per immagazzinare le misure
$ g++ -o array -std=c++11 array.cxx
III ) un array dinamico del C per immagazzinare le misure
$ ./array
cout << "a2 = { ";
for (auto e: a2) cout << e << ", ";
cout << " }" << endl;
direttamente implementate come metodi
• inoltre permette di usufruire di un accesso sicuro agli elementi con controlli
for (int i=0; i<10; i++)
cin >> pia[i];
delete pd;
delete [] pia;
• il vantaggio, rispetto agli array del C, è di poter usare funzioni specializzate
a1 = { -1, -1, -1, -1, }
a2 = { 1, 2, 3, 4, }
unsafe: 4198243
Out of Range access!
0. 1 == 1 | 0x7fff618e1f70
1. 2 == 2 | 0x7fff618e1f74
2. 3 == 3 | 0x7fff618e1f78
3. 4 == 4 | 0x7fff618e1f7c
==
==
==
==
0x7fff618e1f70
0x7fff618e1f74
0x7fff618e1f78
0x7fff618e1f7c
Soluzione 1 : usando un vector
// // Acquisice un insieme di misure di una grandezza fisica e calcola
// il valor medio. Usa un vector<double> per immagazzinare le misure
// #include <iostream>
#include <vector>
int main()
{
using namespace std;
vector<double> data;
double misura;
while(cin >> misura)
data.push_back(misura);
// Calcoliamo la somma
double sum = 0.0;
for (auto e : data)
sum += e;
Soluzione 2 : usando un contenitore array
// Acquisice un insieme di misure di una grandezza fisica e calcola
// il valor medio. Usa un array<T,int> per immagazzinare le misure
#include <iostream>
#include <array>
int main()
{
using namespace std;
const int n_max = 10;
cout << "Numero massimo di misure: " << n_max << endl;
array<double, n_max> data;
$ g++ -std=c++11 mean_vect.cxx
int cnt = 0;
while( cnt < n_max && (cin >> data.at(cnt)) )
$ ./a.out
2.3 3.4 5.6 7.8 1.2 1.3 1.5
Misure inserite: 7
Media: 3.3
cout << "Misure inserite: " << data.size() << endl;
cout << "Media: " << sum/data.size() << endl;
return 0;
}
}
Soluzione 3 : usando un array dinamico
// Acquisice un insieme di misure di una grandezza fisica e calcola
// il valor medio. Usa un array dinamico per immagazzinare le misure
#include <iostream>
int main()
{
using namespace std;
cout << "Inserire il numero delle misure: ";
int n;
cin >> n;
double * data = new double[n];
double misura;
int i = 0;
while(i < n) {
cin >> data[i];
++i;
}
// Calcoliamo la somma
double sum = 0.0;
for (int i=0; i<n; i++)
sum += data[i];
cout << "Media: " << sum/n << endl;
return 0;
}
$ g++ -std=c++11 mean_dynarray.cxx
$ ./a.out
Inserire il numero delle misure: 7
2.3 3.4 5.6 7.8 1.2 1.3 1.5
Media: 3.3
cnt++;
cout << "Misure acquisite: " << cnt << endl;
// Calcoliamo la somma
double sum = 0.0;
$ g++ -std=c++11 mean_array.cxx
for (int i=0; i<cnt; i++)
sum += data.at(i);
$ ./a.out
cout << "Media: " << sum/cnt << endl;
2.3 3.4 5.6 7.8 1.2 1.3 1.5
Misure acquisite: 7
return 0;
Media: 3.3