Allocatable Arrays#
The allocatable
attribute provides a safe way for memory handling.
In comparison to variables with pointer
attribute the memory is managed
automatically and will be deallocated automatically once the variable goes
out-of-scope. Using allocatable
variables removes the possibility to
create memory leaks in an application.
They can be used in subroutines to create scratch or work arrays, where automatic arrays would become too large to fit on the stack.
real(dp), allocatable :: temp(:)
allocate(temp(10))
The allocation status can be checked using the allocated
intrinsic
to avoid uninitialized access
subroutine show_arr(arr)
integer, allocatable, intent(in) :: arr(:)
if (allocated(arr)) then
print *, arr
end if
end subroutine show_arr
To allocate variables inside a procedure the dummy argument has to carry
the allocatable
attribute. Using it in combination with intent(out)
will deallocate previous allocations before entering the procedure:
subroutine foo(lam)
real(dp), allocatable, intent(out) :: lam(:)
allocate(lam(5))
end subroutine foo
The allocated array can be used afterwards like a normal array
real(dp), allocatable :: lam(:)
call foo(lam)
An already allocated array cannot be allocated again without prior deallocation. Similarly, deallocation can only be invoked for allocated arrays. To reallocate an array use
if (allocated(lam)) deallocate(lam)
allocate(lam(10))
Passing allocated arrays to procedures does not require the allocatable
attribute
for the dummy arguments anymore.
subroutine show_arr(arr)
integer, intent(in) :: arr(:)
print *, arr
end subroutine show_arr
subroutine proc
integer :: i
integer, allocatable :: arr
allocate(arr(5))
do i = 1, size(arr)
arr(i) = 2*i + 1
end do
call show_arr(arr)
end subroutine proc
Passing an unallocated array in this context will lead to an invalid memory access.
Allocatable arrays can be passed to optional
dummy arguments -- if they are unallocated
the argument will not be present. The allocatable
attribute is not limited to
arrays and can also be associated with scalars, which can be useful in combination
with optional
dummy arguments.
Allocations can be moved between different arrays with allocatable
attribute
using the move_alloc
intrinsic subroutine.
subroutine resize(var, n)
real(wp), allocatable, intent(inout) :: var(:)
integer, intent(in), optional :: n
integer :: this_size, new_size
integer, parameter :: inital_size = 16
if (allocated(var)) then
this_size = size(var, 1)
call move_alloc(var, tmp)
else
this_size = initial_size
end if
if (present(n)) then
new_size = n
else
new_size = this_size + this_size/2 + 1
end if
allocate(var(new_size))
if (allocated(tmp)) then
this_size = min(size(tmp, 1), size(var, 1))
var(:this_size) = tmp(:this_size)
end if
end subroutine resize
Finally, allocations do not initialize the array. The content of the uninitialized array is most likely just the bytes of whatever was previously at the respective address. The allocation supports initialization using the source attribute:
real(dp), allocatable :: arr(:)
allocate(arr(10), source=0.0_dp)
The source
keyword supports scalar and array valued variables and constants.