tipo* nome_array = new
tipo[numero_elementi]
|
// ex7_3_1 #include <iostream.h> void main() { int n, i; cout << "numero elementi? "; cin >> n; // double v[n]; // NO! n non e` costante double* v = new double[n]; // ok //chiede all'utente di immettere gli elementi di v for (i = 0; i < n; i++) { cout << "? "; cin >> v[i]; } // stampa il vettore v for (i = 0; i < n; i++) cout << "v[" << i << "]: " << v[i] << "\n"; }
esempio di output:
numero elementi? 4
? 5
? -3
? 7
? 19
v[0]: 5
v[1]: -3
v[2]: 7
v[3]: 19
Questo esempio mostra come si può decidere la dimensione di un array in fase
di esecuzione; lo statement commentato double v[n]
non è
corretto in quanto la creazione di array non dinamici suppone che la
dimensione di essi sia nota a priori, in fase di scrittura del programma; il
motivo dipende, come già detto, dal fatto che il compilatore deve sapere in
fase di compilazione quanta memoria occupare nello stack.
Per quanto riguarda le matrici, il metodo di allocazione è leggermente diverso: non possiamo allocare ``con un solo colpo'' una matrice dinamicamente, per cui dobbiamo utilizzare uno stratagemma. Una matrice può essere vista come un vettore costruito mettendo l'una di seguito all'altra tutte le righe di essa; in questa maniera basta allocare dinamicamente un vettore, ricordandoci di stare trattando con una matrice. Per semplificarci la vita, possiamo scrivere una funzione che accetta gli indici dell'elemento di una matrice e il numero delle sue colonne, e restituisca l'indice del vettore corrispondente:
// ex7_3_2 #include <iostream.h> int indice (int i, int j, int colonne) { return i * colonne + j; } void main() { int i, j; // contatori per i for int righe, colonne; cout << "#righe? "; cin >> righe; cout << "#colonne? "; cin >> colonne; double* m = new double[righe * colonne]; cout << "scrivi PER RIGHE la matrice:\n"; // ingresso elementi della matrice for (i = 0; i < righe; i++) { cout << "? "; for (j = 0; j < colonne; j++) cin >> m[indice(i, j, colonne)]; } // stampa matrice for (i = 0; i < righe; i++) { for (j = 0; j < colonne; j++) cout << m[indice(i, j, colonne)] << "\t"; cout << "\n"; } }
esempio di output:
#righe? 3
#colonne? 4
scrivi PER RIGHE la matrice:
? 5 -1 7 0
? 3 0 9 13
? 4 -7 2 1
5 | -1 | 7 | 0 | |
3 | 0 | 9 | 13 | |
4 | -7 | 2 | 1 |
La funzione indice
ha come unico compito quello di elaborare le
coordinate che riceve, unitamente al numero delle colonne della matrice, e
tornare l'indice del corrispondente vettore; in questa maniera possiamo
gestire le matrici allocate dinamicamente come se fossero automatiche, avendo
l'accortezza di usare sempre la funzione indice
per ottenere il giusto
indice dell'elemento cercato. Si risponda alla seguente domanda: perché non è necessario passare anche il numero di righe alla funzione indice
?
Abbiamo visto come allocare nello heap vettori (e matrici), tramite l'operatore new; deallocare un array dinamico è altrettanto semplice che deallocare una semplice variabile: basta utilizzare l'operatore delete[], la cui funzione è unicamente quella di segnare tutta la memoria occupata dall'array come libera. Vediamo un esempio:
// ex7_3_3 #include <iostream.h> #include <stdlib.h> #include <time.h> const int MAX = 90; void casuali (int* v, int n) { for (int i = 0; i < n; i++) v[i] = rand() % MAX + 1; } void stampa (int* v, int n) { for (int i = 0; i < n; i++) cout << v[i] << " "; } void main() { srand( time(0) ); int* n = new int; cout << "? "; cin >> *n; int* v = new int[*n]; casuali (v, *n); stampa (v, *n); delete n; // delete v; // NO! v e` un array delete[] v; // ok }
esempio di output:
? 6
12 40 2 23 59 32
Si faccia bene attenzione: se avessimo utilizzato lo statement delete
,
esso non avrebbe tornato nessun messaggio di errore; infatti il programma
avrebbe eseguito l'operazione di deallocazione solo sulla prima cella
del vettore v
, creando una montagna di garbage: tutti gli elementi
tranne il primo sarebbero stati inaccessibili e non deallocabili; si cerchi
dunque di ricordare sempre di utilizzare l'operatore delete[] per gli array dinamici.
La possibilità di creare array dinamici risolve anche il problema delle stringhe: è possibile ora creare stringhe dimensionate correttamente per il dato che esse devono contenenere, semplicemente allocandole dinamicamente.
// ex7_3_4 #include <iostream.h> #include <string.h> void main() { char buffer[50]; char *nome, *cognome, *residenza; cout << "nome? "; cin >> buffer; nome = new char[strlen(buffer) + 1]; // nota: il +1 e` per il carattere di fine stringa strcpy (nome, buffer); cout << "cognome? "; cin >> buffer; cognome = new char[strlen(buffer) + 1]; strcpy (cognome, buffer); cout << "residenza? "; cin >> buffer; residenza = new char[strlen(buffer) + 1]; strcpy (residenza, buffer); }
esempio di output:
nome? Lewis
cognome? Carrol
residenza? Wonderland
In questo esempio abbiamo mostrato una possibile strada per creare stringhe
della opportuna dimensione: si crea una stringa che è ragionevolmente adatta
a contenere una qualunque delle successive (buffer
nel nostro esempio)
e la si utilizza come ingresso del cin
; volta per volta poi si alloca
un array di caratteri che possa contenere la stringa attualmente in
buffer
, dandole come dimensione la lunghezza di buffer
più una
unità per il carattere di terminazione stringa ('\0'
); si copia
buffer
nella stringa appena creata.
enum Colori { ROSSO, VERDE, BLU, CIANO, MAGENTA, GIALLO, BIANCO, NERO } |
time
, srand
e
rand
) e lo si stampi;