Array


Gli array Fortran corrispondono a insiemi di variabili identificate da un nome unico e da uno o più indici interi. Il numero di indici viene indicato come il rango (rank) dell' array.
Oltre al numero di indici, un array viene caratterizzato dalla sua misura o taglia (size) e cioè il numero totale di componenti dell'array; dall' estensione su ciascun indice (ovvero il numero di valori diversi di quell'indice ); dai valori minimi e massimi dei valori su ciascun indice (lower e upper bound) e dalla sua forma (shape) ovvero la sequenza delle estensioni per ciascun indice.

Si possono dichiarare array in corrispondenza di ciascuno dei 5 tipi dati primitivi. Per farlo, occorre aggiungere l' attributo dimension alle dichiarazioni.

Ad esempio

integer, dimension(10) :: a,b

real, dimension(-5:5) :: x

real, dimension(0:15) :: y

complex,dimension(12) :: z

logical,dimension(-10:10) :: lg

character(len=80),dimension(20) :: string


Le precedenti dichiarazioni corrispondono tutte ad array con un solo indice (array di rango 1). La prima corrisponde a due array di interi di  estensione 10, taglia 10, di indici minimo e massimo pari a 1 e 10 e di forma 10; la seconda e la terza a due array di real di estensione 11 e 16 rispettivamente, pari alla taglia, di indice inferiore -5 il primo e 0 il secondo e superiore 5 il primo e 15 il secondo;  poi c'è un array di variabili logiche (estensione 21) ed infine un array di 20 componenti character, ciascuna delle quali può immagazzinare il valore di un character lungo 80 caratteri.

Per array di rango superiore (il numero di indici massimo possibile in Fortran è 15 nello standard 2008, 7 in quelli precedenti, a partire dal 77), si separano gli intervalli di variabilità dei diversi indici mediante una virgola (,). Es:

real,dimension(10 , 0:9 ,  -10:10) :: A

dichiara A come variabile a 3 indici (array di rango 3) , il primo variabile tra 1 e 10, il secondo tra 0 e 9 ed il terzo tra -10 e 10. La forma dell' array e': [10,10,21]

Questo meccanismo di dichiarazione, corrisponde anche alla allocazione delle corrispondenti locazioni di memoria da parte del compilatore, al momento della compilazione.

Tuttavia, potrebbe essere più utile rimandare l' allocazione della memoria al tempo in cui il programma viene eseguito. Soprattutto se le necessità di memoria possono variare da un' esecuzione all' altra.

Tale meccanismo (allocazione dinamica) comporta in primo luogo di modificare la dichiarazione dell' array:

   1. al posto dell' estensioni o dei limiti inferiori e superiori di ciascun indice dell' array, si mettono dei "due punti" (:), separati da virgole, tanti quanti sono gli indici.
   2. Si aggiunge l' attributo allocatable alla dichiarazione di tipo dati.

Es:

integer,dimension(:,:), allocatable :: a

integer,dimension(:) , allocatable :: b

Quando, nel programma occorrerà allocare memoria, l' istruzione sarà, p.es.:

allocate(a(N,M),b(-N:N))

Se non fosse disponibile la memoria richiesta, nel momento in cui si cercasse di accedervi si verificherebbe una condizione di errore che farebbe arrestare l'esecuzione del processo.
Se la memoria allocata non servisse più, potrebbe essere rilasciata esplicitamente mediante il comando

deallocate(a,b)

Va tuttavia tenuto presente che un programma che termina rilascia comunque tutta la memoria al sistema operativo, anche in assenza di un deallocate esplicito. Pertanto, di norma la deallocazione esplicita di array viene eseguita solo quando occorre riutilizzare gli stessi nomi di array ma con estensionii e/o limiti diversi.
Con lo standard 2003 è stata introdotta la possibilità di allocazione e riallocazione automatica:
ogni volta che ad un array allocabile viene assegnata un'espresssione a valori array, se l'array non era allocato o se era allocato con estensiopne diversa, viene (ri0allocato con estensione pari a quella dell' espressione a destra dell'assegnazione.

La memorizzazione di array di rango maggiore di uno avviene "per colonne". Ovvero l' indice dell' array che varia più velocemente è quello più a sinistra.
In tal modo, p.es., una matrice viene immagazzinata per colonne. Una matrice 2x3 avrà dunque gli elementi memorizzati nel seguente ordine:
a11,a21,a12,a22,a13,a23.

Tenendo presente l' ordine di memorizazione, le istruzioni di input/output (I/O) possono essere basate sul nome dell' array o usare le singole componenti o sezioni dello stesso.

Costruttori di array


Se ad un array si intende assegnare lo stesso valore per tutte le componenti è sufficiente assegnare il valore al nome dell'array.
Es:
x = 1.0

Se invece si intende cambiare i valori si può usare il cosiddetto costruttore di array: si elencano i valori delle varie componenti dell'array, separati da virgole e tra (/ e /) oppure parentesi quadre [ ]. Es:

a = (/ 1, 2, 3, 4, 5 /)
oppure
a = [1,2,3,4,5]

All'interno di un costruttore di array si possono usare cicli do impliciti:

a= [(i, i =1,10)]

nel' ipotesi che a  abbia 10 componenti, o, ancora meglio:

a= [(i, i =1,size(a))]

riempie l'array a con i primi   interi consecutivi a partire da 1.

Per array di rango maggiore di uno occorre combinare il costruttore di array di rango 1 con la funzione intrinseca RESHAPE che riassembla un array di rango 1 secondo la shape data come secondo argomento. L' ordine dei dati è quello di default in mancanza di ulteriori argomenti. Può tuttavia essere presente l' argomento opzionale order cui va associato un array che contiene l' ordine di riempimento delle varie dimensioni dell' array. P.es il seguente programma inizializza una matrice riempiendo la matrice "per righe" e verificando che, scritta "per righe" riproduca la matrice originaria.

program ac
implicit none
integer :: i
integer,dimension(3,2) :: x = reshape( &
 [ 1, 2 &
 , 3, 4 &
 , 5, 6 ] , shape(x), order= [2,1] ) ! order vincola il secondo indice a variare piu' in fretta del primo
             ! e quindi a riempire prima le righe e poi le colonne
do i=1,size(x,1)
 print*,x(i,:)
end do
end program ac


La maggior parte delle funzioni di libreria di tipo numerico, se chiamate con argomento array ritornano al programma chiamante un array della stessa forma e le cui componenti sono i valori della funzione nei corrispondenti punti.


Funzioni intrinseche per manipolazione di array

Esistono di diverse funzioni intrinseche per la manipolazione di array. Diamo qui un elenco delle più utilizzate rinviando alla documentazione del linguaggio per elenchi completi e maggiori dettagli.