Fortran allocatable arrays
last modified November 14, 2026
An allocatable array gets its shape while the program runs, from a value that
is only known then: the number of lines in a file, the length of a command-line
argument, the size of a grid read from a configuration. The declaration fixes
the type and the rank and leaves the bounds open with a colon, and
allocate supplies the bounds later. The compiler keeps track of
whether the array currently has storage, and modern Fortran reallocates it
automatically when an assignment needs a different shape. This article shows
allocation, deallocation, error handling, and the idioms that grow an array
safely.
Allocating and deallocating
The declaration integer, allocatable :: a(:) creates an array
descriptor but no elements. allocate(a(5)) reserves storage for
five integers, after which the array can be used like any other, and
deallocate(a) releases the storage. The allocated
inquiry tells whether the descriptor currently points at storage; it is false
before the allocation and true after it.
program a1
implicit none
integer, allocatable :: a(:)
integer :: i
print *, 'allocated before:', allocated(a)
allocate(a(5))
print *, 'allocated after: ', allocated(a)
a = [(i * 10, i = 1, 5)]
print *, a
deallocate(a)
print *, 'allocated at the end:', allocated(a)
end program a1
Before the allocation the array has no elements and cannot be indexed. After
it, the constructor fills the five positions with 10, 20, 30, 40 and 50. The
last report is false again, because deallocate returned the
memory to the system. Deallocating an array that is not allocated is an error,
and so is allocating one twice, which is why the next section checks the
status.
$ gfortran a1.f90 -o a1
$ ./a1
allocated before: F
allocated after: T
10 20 30 40 50
allocated at the end: F
When allocation fails
allocate accepts stat= and errmsg=
arguments. With stat, a failure does not terminate the program;
the variable receives zero on success and a non-zero code on failure, and
errmsg receives a message that describes the problem. The
numerical code is processor-dependent, so a program should test
stat /= 0 rather than a particular value, and it should only
read errmsg after a failure.
program a2
implicit none
integer, allocatable :: a(:)
integer :: stat
character(len=80) :: msg
allocate(a(3), stat=stat, errmsg=msg)
print *, 'first allocate: stat =', stat
allocate(a(4), stat=stat, errmsg=msg)
print *, 'second allocate: stat =', stat
print *, trim(msg)
end program a2
The first allocation succeeds, so the status is 0 and the message is not
used. The second one tries to allocate the same array again without
deallocating it first, which is invalid, so the status becomes non-zero and
the message explains the reason. A real program would branch on
stat /= 0, report the message, and either stop or pick a smaller
size.
$ gfortran a2.f90 -o a2 $ ./a2 first allocate: stat = 0 second allocate: stat = 5014 Attempt to allocate an allocated object
Copying with source and mold
source= allocates an array with the shape of an existing one and
copies its values, so the new array is immediately usable.
mold= takes only the type, kind and shape from the argument; the
contents of the new array are undefined until they are assigned. Use
source when the values are wanted and mold when only
the geometry is needed, because source performs a copy.
program a3
implicit none
integer :: fixed(4)
integer, allocatable :: a(:), b(:)
fixed = [2, 4, 6, 8]
allocate(a, source=fixed)
allocate(b, mold=fixed)
b = 0
print *, 'a:', a
print *, 'shape of b:', shape(b)
print *, 'b:', b
end program a3
The array a receives both the shape and the values of
fixed, so it prints 2, 4, 6 and 8. The array b gets
the same shape of four elements, but its values are whatever the memory
contained, which is why the program assigns zero before printing. The shape
report shows that mold did its job: four elements of the right
type.
$ gfortran a3.f90 -o a3 $ ./a3 a: 2 4 6 8 shape of b: 4 b: 0 0 0 0
Automatic reallocation on assignment
An allocatable array does not have to be allocated before it is assigned. An intrinsic assignment to an unallocated allocatable allocates it with the shape of the right-hand side, and if it is already allocated with a different shape, the runtime reallocates it. Assigning a section of the array to the array itself works too, because the right-hand side is evaluated before the assignment. The array is first given a zero-sized allocation here, so that its descriptor is initialised; GNU Fortran otherwise warns that the descriptor may be used uninitialized when the assignment allocates it.
program a4
implicit none
integer, allocatable :: a(:)
allocate(a(0))
a = [1, 2, 3]
print *, 'size:', size(a), 'values:', a
a = [a, 4, 5]
print *, 'size:', size(a), 'values:', a
a = a(2:4)
print *, 'size:', size(a), 'values:', a
end program a4
The first assignment grows the empty array to three elements, and the second
builds a new five-element constructor from the old values and the two new
ones. The third assignment takes a section of the array, evaluates it, and
only then reallocates the left side to a length of three. Each line prints the
new size and contents, and no explicit allocate follows the first
one.
$ gfortran a4.f90 -o a4 $ ./a4 size: 3 values: 1 2 3 size: 5 values: 1 2 3 4 5 size: 3 values: 2 3 4
Growing an array in a loop
Appending to an allocatable array with a = [a, item] is the
simplest way to collect an unknown number of values. Every iteration builds a
new array and copies the old elements, so the cost grows with the square of
the final length. That is fine for a few thousand elements and wasteful for
millions; in the second case, allocate a generous size, fill it with a counter,
and copy the used part at the end.
program a5
implicit none
integer, allocatable :: evens(:)
integer :: i
allocate(evens(0))
do i = 1, 10
if (mod(i, 2) == 0) then
evens = [evens, i]
end if
end do
print *, 'count:', size(evens)
print *, evens
end program a5
The loop keeps the even numbers from 1 to 10, appending one at a time, and the final array has five elements. The zero-sized allocation before the loop gives the constructor something to extend; appending to an array that is not allocated at all would create a new one on the first iteration, which works but triggers the compiler warning described above. The output shows the count and then the collected values.
$ gfortran a5.f90 -o a5
$ ./a5
count: 5
2 4 6 8 10
Moving an allocation
move_alloc(from, to) transfers the storage of one allocatable
array to another and leaves the source unallocated. Nothing is copied: only
the descriptor moves, which makes the call cheap even for a large array. It is
the standard way to return an array from a procedure without a copy, and it
also replaces the contents of the destination, deallocating it first if
necessary.
program a6
implicit none
integer, allocatable :: a(:), b(:)
allocate(a(3))
a = [1, 2, 3]
print *, 'before: a allocated', allocated(a), ' b allocated', allocated(b)
call move_alloc(a, b)
print *, 'after: a allocated', allocated(a), ' b allocated', allocated(b)
print *, 'b:', b
end program a6
Before the call only a is allocated. Afterwards b
owns the three values and a is unallocated, so the allocation
status of the two variables has been swapped. The values are still 1, 2 and 3,
and no element was copied. move_alloc is a subroutine, so it is
called with call, and both arguments must be allocatable.
$ gfortran a6.f90 -o a6 $ ./a6 before: a allocated T b allocated F after: a allocated F b allocated T b: 1 2 3
Allocatable function results
A function may return an allocatable array, which frees the caller from
knowing the result size in advance. The result variable is declared
allocatable in the function and allocated inside the body, and
the caller assigns the call to an allocatable array of its own; the assignment
takes care of the shape. This pattern keeps the size calculation in the
procedure that knows the answer.
program a7
implicit none
integer, allocatable :: squares(:)
allocate(squares(0))
squares = first_squares(6)
print *, squares
contains
function first_squares(n) result(r)
integer, intent(in) :: n
integer, allocatable :: r(:)
integer :: i
allocate(r(n))
r = [(i * i, i = 1, n)]
end function first_squares
end program a7
The function allocates its result with the requested length and fills it with the squares of 1 to 6, so the caller receives 1, 4, 9, 16, 25 and 36. The caller's array starts as a zero-sized allocation for the reason given earlier, and the assignment reallocates it to the six elements of the result. The compiler may move the function result into the caller's array instead of copying it.
$ gfortran a7.f90 -o a7
$ ./a7
1 4 9 16 25 36
Zero-sized arrays
An allocation of zero elements is legal and produces an array that is
allocated but has no elements. It is a useful representation of an empty
result: size is zero, sum is zero, and a loop over
the array body never runs, so no special case is needed for the empty input.
allocated is true, which distinguishes "allocated but empty" from
"never allocated".
program a8
implicit none
integer, allocatable :: a(:)
allocate(a(0))
print *, 'size:', size(a)
print *, 'sum: ', sum(a)
print *, 'allocated:', allocated(a)
end program a8
The array has no elements, so the size is 0 and the sum is 0, yet it counts as
allocated. Functions that build a result from a mask, such as
pack, return a zero-sized array when nothing matches, and code
that sums or loops over the result needs no guard. The distinction matters
when an unallocated result would be an error but an empty one is a valid
answer.
$ gfortran a8.f90 -o a8 $ ./a8 size: 0 sum: 0 allocated: T
Next steps
The next article, Fortran array arguments, shows how allocatable and fixed arrays are passed to procedures, and how the shape travels with an assumed-shape argument. The array intrinsics article uses the functions that often produce these arrays, and the arrays article covers the fixed-size declarations that allocatable arrays extend. A later article on derived types shows allocatable components inside a type.
Source
Fortran 2018 standard (J3/18-007r1)
In this article we have allocated and deallocated arrays, handled allocation
failures with stat and errmsg, copied arrays with
source and mold, relied on automatic reallocation in
assignments, grown an array in a loop, moved an allocation without copying,
returned an allocatable array from a function, and used a zero-sized array as
an empty result.
Author
List all Fortran tutorials.