Array Multidimensionali Statici in Object Pascal
- Un array multidimensionale statico è dichiarato specificando più dimensioni nell'array.
- Ogni dimensione ha i propri limiti inferiori e superiori.
- Gli elementi dell'array sono accessibili utilizzando tutti gli indici specificati.
- La sintassi per dichiarare un array multidimensionale è:
var nome_array: array[limite_inferiore1..limite_superiore1, limite_inferiore2..limite_superiore2, ...] of tipo_di_dato;
- L'accesso agli elementi dell'array richiede l'uso di tutti gli indici. Esistono due modi equivalenti per accedere agli elementi:
Matrice[i, j] := valore; Matrice[i][j] := valore; // Equivalente
Array multidimensionali statici
Un array può avere più di una dimensione, implementando, così, una matrice o un cubo piuttosto che una semplice sequenza.
La sintassi generale per dichiarare un array multidimensionale è:
var
nome_array: array[limite_inferiore1..limite_superiore1,
limite_inferiore2..limite_superiore2,
...] of tipo_di_dato;
Dove limite_inferiore1..limite_superiore1
definisce il primo indice e i suoi limiti, limite_inferiore2..limite_superiore2
definisce il secondo indice e i suoi limiti, e così via. Ogni indice può avere limiti diversi. tipo_di_dato
è il tipo di dato degli elementi dell'array.
Possiamo anche definire un tipo di array multidimensionale usando la parola chiave type
, come mostrato in precedenza per gli array monodimensionali:
type
nome_tipo_array = array[limite_inferiore1..limite_superiore1,
limite_inferiore2..limite_superiore2,
...] of tipo_di_dato;
var
nome_array: nome_tipo_array;
Vediamo di chiarire con un esempio. Supponiamo di voler memorizzare le temperature registrate ogni ora per ogni giorno di un mese. Un modo per farlo è utilizzare un array bidimensionale, dove il primo indice rappresenta il giorno del mese (1-31) mentre il secondo indice rappresenta l'ora del giorno (1-24). La dichiarazione dell'array sarebbe:
var
Temperature: array[1..31, 1..24] of Integer;
Così facendo, abbiamo dichiarato un array chiamato Temperature
che può contenere 744 valori interi (24 ore x 31 giorni).
Per accedere a un elemento specifico dell'array, si utilizzano entrambi gli indici. Ad esempio, per impostare la temperatura registrata alle 2 del pomeriggio (14:00) del 18° giorno del mese a 25 gradi, si scrive:
Temperature[18, 14] := 25;
Analogamente, possiamo scorrere tutti i valori dell'array utilizzando cicli annidati e le funzioni Low
e High
per ottenere i limiti degli indici.
Ad esempio, supponiamo di voler calcolare la temperatura media giornaliera per ogni giorno del mese. Possiamo farlo con il seguente codice:
var
giorno, ora: Integer;
somma, media: Real;
Temperature: array[1..31, 1..24] of Integer;
begin
{ Itera su ogni giorno del mese }
for giorno := Low(Temperature) to High(Temperature) do
begin
somma := 0;
{ Itera su ogni ora del giorno }
for ora := Low(Temperature[giorno]) to High(Temperature[giorno]) do
begin
somma := somma + Temperature[giorno, ora];
end;
media := somma / (High(Temperature[giorno]) - Low(Temperature[giorno]) + 1);
Writeln('Temperatura media del giorno ', giorno, ': ', media:0:2);
end;
end;
Da notare l'utilizzo di Low(Temperature[giorno])
e High(Temperature[giorno])
per ottenere i limiti del secondo indice (ore) per un dato giorno. Infatti, Low
e High
possono essere utilizzati per ottenere i limiti di qualsiasi dimensione dell'array. Se non si specifica un indice, Low
e High
si riferiscono al primo indice.
Ricapitolando:
Array Multidimensionali Statici
In Object Pascal, un array multidimensionale statico è dichiarato specificando più dimensioni nell'array. Ogni dimensione ha i propri limiti inferiori e superiori. Gli elementi dell'array sono accessibili utilizzando tutti gli indici specificati.
La sintassi per dichiarare un array multidimensionale è:
var
nome_array: array[limite_inferiore1..limite_superiore1,
limite_inferiore2..limite_superiore2,
...] of tipo_di_dato;
L'accesso agli elementi dell'array richiede l'uso di tutti gli indici. Ad esempio, per un array bidimensionale Matrice
, si accede a un elemento specifico con Matrice[i, j]
, dove i
e j
sono gli indici delle rispettive dimensioni. Oppure si può usare la notazione con parentesi quadre annidate, come Matrice[i][j]
, che è equivalente:
Matrice[i, j] := valore;
Matrice[i][j] := valore; // Equivalente
Gli array statici multidimensionali presentano, tuttavia, una serie di problemi:
- In primo luogo, come gli analoghi array monodimensionali, gli array statici hanno una dimensione fissa che non può essere modificata durante l'esecuzione del programma. Questo può essere limitante se non si conosce in anticipo la quantità di dati da gestire.
- Gli array multidimensionali statici occupano molta memoria, il che, in generale, dovrebbe essere evitato. La variabile
Temperature
richiede 744 Integer, che occupano 4 byte ciascuno, ossia circa 3Kb. Allocare un blocco così grande nella memoria globale o nello stack come nell'esempio, può sembrare poca cosa (specialmente al giorno d'oggi dove le memorie RAM sono abbondanti). Tuttavia, allocare grandi blocchi di memoria nello stack può portare a problemi di overflow dello stack in applicazioni più complesse o in ambienti con risorse limitate.
Il secondo problema è particolarmente rilevante quando si lavora con array di dimensioni maggiori o con più dimensioni. Ad esempio, se si volesse memorizzare le temperature per un intero anno (12 mesi), si potrebbe essere tentati di dichiarare un array tridimensionale come segue:
TAnno: array[1..12, 1..31, 1..24] of Integer;
Così facendo, l'array TAnno
richiederebbe 8,928 Integer (12 mesi x 31 giorni x 24 ore), che occupano quasi 35KB di memoria. Il problema diventa ancora più evidente quando, come vedremo, vogliamo passare questi array come parametri a funzioni o procedure.
Un array dinamico, invece, utilizza la memoria heap e offre molta più flessibilità in termini di allocazione e gestione della memoria.
Definizione di Tipi di Array Intermedi
Nell'esempio di sopra, quando abbiamo definito l'array Temperature
per memorizzare le temperature giornaliere, abbiamo usato la seguente definizione:
var
Temperature: array[1..31, 1..24] of Integer;
Avremmo anche potuto definire un tipo di array per rappresentare le temperature giornaliere:
type
TTemperatureGiornaliere = array[1..31, 1..24] of Integer;
var
Temperature: TTemperatureGiornaliere;
Dato che l'array multidimensionale può essere visto come un array di array, possiamo definire tipi intermedi per ogni dimensione dato che il tipo base è sempre un Integer
. Per esempio, possiamo definire un tipo per le temperature di un singolo giorno (24 ore) e poi usare quel tipo per definire un tipo per le temperature di un mese (31 giorni):
type
TTemperatureGiornaliere = array[1..24] of Integer;
TTemperatureMensili = array[1..31] of TTemperatureGiornaliere;
var
Temperature: TTemperatureMensili;
Definizione di Tipi di Array Intermedi
In Object Pascal è possibile definire tipi di array intermedi per rappresentare strutture dati complesse. Questo approccio migliora la leggibilità del codice e facilita la gestione degli array multidimensionali.
La sintassi per definire tipi di array intermedi è:
type
nome_tipo_array1 = array[limite_inferiore1..limite_superiore1] of tipo_di_dato;
nome_tipo_array2 = array[limite_inferiore2..limite_superiore2] of nome_tipo_array1;
...
var
nome_array: nome_tipo_array2;
L'importanza dell'utilizzare tipi intermedi risiede nel fatto che gli array sono compatibili nel tipo solo se si riferiscono allo stesso esatto nome di tipo (cioè esattamente la stessa definizione di tipo), non se le loro definizioni di tipo si riferiscono casualmente alla stessa implementazione.
Questa regola di compatibilità del tipo è la stessa per tutti i tipi in Object Pascal, con solo alcune eccezioni specifiche.
Per esempio, la seguente istruzione copia le temperature del secondo giorno al terzo giorno di un altro array:
var
Mese1, Mese2: TTemperatureMensili;
begin
{ ... }
Mese2[3] := Mese1[2];
{ ... }
end;
Possiamo farlo perché Mese1
e Mese2
sono entrambi dichiarati come TTemperatureMensili
, quindi i loro elementi (che sono di tipo TTemperatureGiornaliere
) sono compatibili nel tipo.
Ciò vale anche se usiamo il tipo TTemperatureMensili
per dichiarare un array che contiene le temperature di più mesi:
type
TTemperatureAnnuali = array[1..12] of TTemperatureMensili;
var
Anno1: TTemperatureAnnuali;
Mese1: TTemperatureMensili;
begin
{ ... }
Mese1 := Anno1[3]; { Copia il terzo mese dell'anno in Mese1 }
{ ... }
end;
Questa cosa non può essere fatta se si tenta di copiare un array che non è stato dichiarato con lo stesso nome di tipo.
Prendiamo l'esempio che segue:
var
Mese1: TTemperatureMensili;
Mese2: array[1..31, 1..24] of Integer;
begin
{ ... }
Mese2[2] := Mese1[3]; { Errore di compilazione! }
{ ... }
end;
Questo codice causa un errore di compilazione perché Mese1
e Mese2
non sono stati dichiarati con lo stesso nome di tipo, anche se le loro definizioni di tipo sono identiche. La riga evidenziata causerebbe l'errore:
Error: Incompatible types: 'array[1..31] of array[1..12] of Integer' and
'TTemperatureMensili'
Ricapitolando:
Compatibilità dei Tipi per Array Multidimensionali Statici
In Object Pascal, gli array sono compatibili nel tipo solo se si riferiscono allo stesso esatto nome di tipo, non se le loro definizioni di tipo si riferiscono casualmente alla stessa implementazione. Questo significa che due array con la stessa struttura ma dichiarati con nomi di tipo diversi non sono considerati compatibili.