An allocatable array is the same as a dynamic array. Its size is not fixed therefore it is not known at compilation time. It is defined at execution time.

It has several advantages compared to an explicit shape. The most important of all is its flexibility. It is also more memory efficient because it is only allocated/deallocated when required.

In Fortran, It is normally preferred over pointers as those are inherently safer (e.g: automatically deallocated at the end of scope). Whilst pointers remain in memory even when leaving its allocation scope.

IMHO you can find below the most useful points to have in mind when using them:

The basics

It is formally declared with the attribute allocatable. Find below the implicit form:

integer, allocatable: grid(:,:)

As well as its explicit form:

integer, allocatable, dimensions(:,:) :: grid

Later on, its dimensions are defined and memory is requested as:

allocate(grid(4,5))

Finally, it is released from memory as:

deallocate(grid)

It is not possible to allocate when it is already done. The same applies for deallocation. Because of this Its status is requested as shown below. The function returns a logical (true/false) value:

if (allocated(grid)) then
  ...
end if

Allocation

As explained before, the array can be easily allocated with the allocate statement. Once done, no value is defined. It’s simplest form:

allocate(newGrid(4,4))

Furthermore, allocate offer more possibilities. Specially when dealing with others arrays. Check below for the options source and mold. Both enable an automatic copy of dimensions and/or values.

Source

Regarding source, it copies the whole grid into newGrid. It includes the dimensions/shape and the values from grid.

allocate(newGrid, source=grid)

Mold

Yet it is not always the case the values are required. For this reason, make use of mold to only copy the dimensions from grid into newGrid. So newGrid values remain undefined.

allocate(newGrid, mold=grid)

Status

By default, when there is a problem allocating a variable an error is raised.

It can be prevented using the optional output argument status. A value is given to errnum once executed: Negative for a problem or 0 if everything runs well. Take into account no error will be raised once this argument is set.

allocate(newGrid, status=errnum)
if (ierrnum /= 0) call doSomething()

Deallocate

Allocation ask to the OS to request new memory for an array. The opposite procedure is called Deallocate. It frees the memory when asked.

DEALLOCATE(myarray)

Move alloc

Moving data across arrays can be expensive. For that reason, there is an efficient way by using the function move_alloc(from, to). However from will be deallocated.

integer, allocatable :: grid(:,:)
integer, allocatable :: newGrid(:,:)
allocate(grid(3,3))
grid = 25
call move_alloc(grid, newGrid)

The subroutine is moving the array reference between both variables. So no “real” data is moved along.

Scope

Any allocatable array is automatically released (deallocated) from memory at the end of scope. For example, at the end of a subroutine when declared locally.

subroutine dosomething(dim)
  integer, intent(in) :: dim
  integer, allocatable :: grid(:)
  allocate(grid(dim))
  ...
  do some computing
  ...
  !< grid is automatically deallocated here
end dosomething

Subroutines

Allocatable arrays can also be passed to subroutines as arguments. It can be given to a subroutine like:

!< declared
integer, allocatable :: grid(:,:)
!< request memory and define its dimensions  
allocate(grid(3,3))
call calculate(grid)

The subroutine can declare it as a dummy array argument (it does not care about certain array attributes). In such case, it won’t be able to reallocate the array variable.

subroutine calculate(array)
  !< array values can be modified but never deallocated
  integer, intent(inout) :: array(:,:)
end subroutine calculate

On the other hand, it can be defined with an explicit argument. Its attribute enforces to pass an allocatable array. Therefore, according to its intent it will be possible to resize it.

subroutine calculate(array)
  !< array values can be modified and array re-allocated    
  integer, allocatable, intent(inout) :: array(:,:)
end subroutine calculate

Intent

Intent statement tells to the subroutine which intentions have the arguments. Find below the available possibilities:

  • In -> (or input) Read only
  • inout -> (or input/output) It can be modified therefore resize allowed.
  • out -> (or output) it must be allocated. In case it is already done It is automatically deallocated.

Comparision

Check this post

Leave a Reply

Your email address will not be published. Required fields are marked *