Pointers
OK, adesso anche nel Fortran ci sono i puntatori (pointer). Siccome questi post sono legati a un programma specifico non ne parlerò adesso, forse in futuro.
Preprocessore
Come per il C è disponibile il preprocessore, quindi #ifdef
, #ifndef
&co. In realtà si usa GCC, sempre lui.
Ricorsività
Adesso una procedura può chiamare sé stessa ricorsivamente, cosa vietata fino al 77 compreso. Ecco per esempio il calcolo del fattoriale.
program nfact ! da Tanja van Mourik implicit none integer :: n integer :: nfactorial do n = 2, 9, 3 print *, n, nfactorial(n) end do end program nfact recursive function nfactorial(n) result(fac) implicit none integer :: fac integer, intent(in) :: n select case(n) case (0:1) fac = 1 case default fac = n * nfactorial(n-1) end select end function nfactorial
Notare il select case
e che la funzione dev’essere dichiarata recursive
.
Operazioni sugli array
Gli array possono essere inizializzati sia con (/
e /)
che con [
e ]
.
Possono essere copiati con una singola istruzione, evitando un do
specifico.
program arr implicit none integer :: a(5) = (/1, 2, 3, 4, 5/) integer :: b(5) = [1, 4, 9, 16, 25] print *, 'inizio' print "(5i3)", a, b a = b ! copia dell'array print "(/, 'dopo la copia')" print "(5i3)", a a(2:5) = a(1:4) a(1) = 0 print "(/, 'dopo lo spostamento')" print "(5i3)", a end
Il tentativo di invertire ‘al volo’ un array da errore, la copia funziona solo per slice (chissà come si dice da noi?).
program arr implicit none integer :: a(5) = (/1, 2, 3, 4, 5/) integer :: b(5) = [1, 4, 9, 16, 25] a(1:5) = b(5:1) print "(5i3)", a, b end
In questo caso si deve ricorrere al solito ciclo.
program arr implicit none integer :: a(5) integer :: b(5) = [1, 4, 9, 16, 25] integer :: i do i = 1, 5 a(i) = b(6 - i) end do print "(5i3)", a, b end
Array dinamici
Copiando da Tanja: alle volte la dimensione di un array non è nota fino all’esecuzione del programma, ecco allora gli array dinamici.
program dynarr implicit none real, allocatable :: a(:,:) integer :: dim1, dim2 integer :: i, j write(*, fmt = '("Give dimensions DIM1 and DIM2: ")', & advance = "NO") read(*, *) dim1, dim2 ! now that the size of a is know, allocate memory for it allocate(a(dim1,dim2)) do i = 1, dim2 do j = 1, dim1 a(j,i) = i*j write(*, fmt = '("a(",i2,",",i2,") = ", f6.2)') & j, i, a(j, i) end do end do deallocate(a) end
Domanda di G. (ripetuta, ecco la risposta): si può continuare a usare quello che si usava una volta? Certo, ecco:
program oldstyle implicit none common /mydat/ numero integer :: i, numero, molt i = 5 numero = 3 print *, i, molt(i) end integer function molt(n) implicit none common /mydat/ mul integer n, d, mul d = mul * n molt = d return !non serve ma si usava end
Il common
è comunque sconsigliato, usare i moduli. Con questi posso importare selettivamente le variabili che mi servono effettivamente, anche con nomi differenti.
program es_only use m_only, only: alpha, b => beta ! b è beta del modulo implicit none integer :: gamm, delta ! gamm e delta NON sono quelli del modulo print *, alpha, b, gamm, delta end module m_only implicit none integer :: alpha = 1, beta = 2, gamm = 3 integer, private :: delta = 4 end module
OK, con questo credo di aver elencato (quasi) tutti le nuove caratteristiche del linguaggio, rispetto al 77. In realtà ho saltato quelle che non credo saranno utilizzate in un caso reale che partirà a breve. Probabilmente posterò ancora un elenco di domande tipiche, tipo questa:
D: con il formato libero puoi mettere i commenti con una C in prima colonna?
R: prova ma no, ecco:
program c_com C questi una volta c sarebbero stati commenti i = 42 print *, i end
Beh, ce ne sono anche di meno banali 😉