Allocazione dinamica: variabili ALLOCATABLE

In f90 gli array possono essere dichiarati con l'attributo ALLOCATABLE. Tale attributo indica che lo spazio per quell'array non viene riservato all'inizio dell'esecuzione del programma ma solo dopo l'esecuzione dell'istruzione ALLOCATE(), in cui si determina anche la dimensione dell'array (denominato quindi "deferred shape array" o "array allocato dinamicamente"). Il rango (cioè il numero delle dimensioni) dell'array deve essere comunque reso noto al momento della compilazione specificandolo nella dichiarazione dell'array stesso.

Una variabile ALLOCATABLE può essere allocata solo nell'unità di programma in cui è dichiarata o, se è dichiarata in un modulo, in una qualsiasi unità di programma che fa USE di quel modulo; in altre parole non è possibile, in una subroutine, allocare un array ricevuto come parametro (sarà possibile farlo in F2003).

Al termine dell'utilizzo o prima di un'eventuale riallocazione dell'array con una dimensione diversa, è opportuno liberare lo spazio con l'istruzione DEALLOCATE(). Esiste poi la funzione intrinseca ALLOCATED() che restituisce un valore logico .TRUE. se il corrispondente argomento è correntemente allocato e viceversa.

PROGRAM rete_oss
USE stazioni
IMPLICIT NONE

CHARACTER (LEN=20), rnome
REAL :: rlon, rlat, rt
INTEGER :: n

READ*,n
CALL alloc_staz(n)

DO WHILE(.TRUE.)
  READ*, rnome, rlon, rlat, rt
  IF (rlon < -361.) EXIT
  CALL aggiungi_staz(rnome, rlon, rlat, rt)
ENDDO

PRINT'(A,I3,A)','Ho letto ',get_nstaz(),' stazioni'
CALL elabora_temp()

CALL dealloc_staz()

END PROGRAM rete_oss
MODULE stazioni
IMPLICIT NONE

INTEGER, PARAMETER :: nstazmax=100
INTEGER :: nstaz = 0
REAL, ALLOCATABLE :: lon(:), lat(:), t(:)
CHARACTER (LEN=20), ALLOCATABLE :: nome(:)
PRIVATE nstaz

CONTAINS

SUBROUTINE alloc_staz(n)
INTEGER, INTENT(IN) :: n

ALLOCATE(lon(n), lat(n), t(n), nome(n))

END SUBROUTINE alloc_staz

SUBROUTINE dealloc_staz()

IF ALLOCATED(lon) THEN
  DEALLOCATE(lon, lat, t, nome)
ENDIF

END SUBROUTINE dealloc_staz

SUBROUTINE aggiungi_staz(nnome, nlon, nlat, nt)
CHARACTER (LEN=*), INTENT(IN) :: nnome
REAL, INTENT(IN) :: nlon, nlat, nt

IF (nstaz < size(lon)) THEN
  nstaz = nstaz + 1
  nome(nstaz) = nnome
  lon(nstaz) = nlon
  lat(nstaz) = nlat
  t(nstaz) = nt
ELSE
  PRINT*,'Raggiunto il massimo delle stazioni'
ENDIF

END SUBROUTINE aggiungi_staz

SUBROUTINE stampa_anag()
INTEGER :: i

DO i = 1, nstaz
  PRINT'(A,2F7.2)',TRIM(nome(i)),lon(i),lat(i)
ENDDO

END SUBROUTINE stampa_anag

SUBROUTINE elabora_temp()

IF (nstaz > 0) THEN
  PRINT'(A,F9.2)','Temperatura media:', SUM(t(1:nstaz))/nstaz
ENDIF

END SUBROUTINE elabora_temp

INTEGER FUNCTION get_nstaz()

get_nstaz = nstaz

END FUNCTION get_nstaz

END MODULE stazioni