Unlike C, which often uses pointers to handle array data, Fortran has arrays which are an intrinsic feature of the language.
Arrays may be declared with addition of the dimension
attribute, e.g.,
program example1
implicit none
real, dimension(3) :: a ! declare a with elements a(1), a(2), a(3)
end program example1
The size of the array is the total number of elements (here 3). The default lower bound is 1 and the upper bound is 3.
real, dimension(-2:1) :: b ! elements b(-2), b(1), b(0), b(1)
Here we specify, explicitly, the lower and upper bounds. The size of this array is 4.
One may specify array values as a constructor
integer, dimension(3), parameter :: s = (/ -1, 0, +1 /) ! F2003 or
integer, dimension(3), parameter :: t = [ -1, 0, +1 ] ! F2008
real, dimension(2,3) :: a ! elements a(1,1), a(1,2), a(1,3)
! a(2,1), a(2,2), a(2,3)
This two-dimensional array (said to have rank 2) has two elements in the first dimension (or extent 2), and 3 elements in the second dimension (extent 3). It is said to have shape (2,3), which is the sequence of extents in each dimension. Its size is 6 elements.
There is an array element order which in which we expect the implementation
to store contiguously in memory. In Fortran this has be left-most
dimension counting fastest. For array a
we expect the order in
memory to be
a(1,1), a(2,1), a(1,2), a(2,2), a(1,3), a(2,3)
that is, the opposite the the convention in C.
A constructor for an array of rank 2 or above might be used, e.g.,
integer, dimension(2,3) :: m = reshape([1,2,3,4,5,6], shape = [2,3])
where we have used the intrinsic function reshape()
.
Check the accompanying example1.f90
to see examples of intrinsic functions
available to interrogate array size and shape at run time.
If we wish to establish storage with shape determined at run time, the allocatable attribute can be used. The rank must be specified:
real, dimension(:, :), allocatable :: a
! ... establish shape required, say (imax, jmax) ...
allocate(a(imax, jmax))
! ... use and then release storage ...
deallocate(a)
Again, this array will take on the default lower bound of 1 in each dimension.
Formally,
allocate(allocate-list [, source = array-expr] [ , stat = scalar-int-var])
The optional source
argument may be used to provide a template for
the newly allocated object (values will be copied). We will return to
this in more detail in the context of dynamic type.
A successful allocation with the optional stat
argument will assign a
value of zero to the argument.
An array declared with the allocatable attribute is initially in
an unallocated state. When allocated, this status will change; this
status can be interrogated via the intrinsic function allocated()
.
integer, dimension(:), allocatable :: m
...
if (allocated(m)) then
! ... we can do something ...
end if
Attempt to deallocate
a variable which is not allocated is an error.
Return again to the program to compute the approximation of pi via
the Gauss-Legendre expansion (last seen in section2.01). You may use
your own version or the new template provided in this directory
(see exercise1.f90
).
Introduce array storage for the quantites a
, b
and t
. Use a
fixed number of terms. Assign appropriate values in a first loop.
In a second loop, compute the approximation of pi at each iteration.
What might you do if you wanted to storage only the number of terms taken to reach a converged answer?