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
© Copyright 2024 ExpyDoc