Arrays

Last updated on 2026-07-21 | Edit this page

Estimated time: 20 minutes

Overview

Questions

  • How are arrays declared?
  • How can array sizes be determined at runtime?

Objectives

  • Understand how to define static and dynamic arrays
  • Diagnose and debug array definitions in simple programs

Declarations


We may declare arrays of intrinsic type with a fairly elastic syntax, e.g.:

FORTRAN

  integer, dimension(10, 2) :: a
  integer, dimension(10, 2) :: b, c, d, e(10, 3)

Note that the declaration e(10, 3) will override the dimension(10, 2) statement, however this mix and match approach is generally discouraged.

One may also omit the dimension attribute:

FORTRAN

  integer, dimension(10, 2) :: a
  integer                   :: b(10, 2)

The two declarations of b(10,2) above are equivalent. If one restricts oneself to one variable declaration per line, then the second form is more concise, and will be preferred in the rest of this course.

Arrays have a rank, a size (the number of elements). The sequence of extents in each dimension is the shape. The array in Fortran is a self-describing object and its properties may be interrogated via intrinsic functions: size(), shape(), lbound(), and ubound().

There is an array element order which has the left-most index counting fastest; we expect this to correspond to contiguous locations in memory.

There are a number of ways one may obtain array sections or array-valued objects which may not be contiguous:

FORTRAN

  integer :: a(5)
  real    :: b(10, 2)

  a(1:5:2)          ! an array section   referencing elements 1, 3, and 5
  a( [1, 3, 5] )    ! a vector subscript referencing elements 1, 3, and 5
  b(1:5, 1)         ! a rank one section of size 5
  b(1:2, 1:2)       ! a rank two section of shape (2, 2)

Limit on number of ranks

Arrays of rank up to 7 were supported (pre-F2008); this was increased to a limit of 15 at F2008. F2018 introduced an intrinsic rank() inquiry function which returns the scalar integer rank of the array argument.

Array constructors


There are a number of ways to provide initial values for array elements:

FORTRAN

  integer, parameter :: j(3) = (/ -1, 0, +1 /)    ! F2003
  integer, parameter :: k(3) = [  -1, 0, +1 ]     ! F2008

One may also use an implied do construction:

FORTRAN

  integer         :: i
  real, parameter :: s(300) = [ (i, i = 1,300) ]
  real            :: t(3)   = [ (2.0*(i*i + 1), i = 1,3) ]

Older code may also see use of the data statement to initialise tables of values. This has the form:

FORTRAN

data data-statement-set [[,] data-statement-set] ...

where the data-statement-set consists of pairs of

FORTRAN

data-statement-object-list / data-statement-value-list /

That is, one associates a list of values with a list of variables, e.g.:

FORTRAN

real a, b, c
data a, b, c / 1.0, 2.0, 3.0 /

The data statement is quite flexible in syntax, but generally can be omitted in favour of array constructors or other “more modern” facilities. The data statement cannot be used to initialise allocatable or pointer variables.

Heap storage


Storage for arrays may be established at run time via the allocatable attribute, e.g.:

FORTRAN

   real, allocatable :: a(:)
   ! ...
   allocate(a(1:nlen))
   ! ...
   deallocate(a)

The allocation status of the array may be interrogated via the intrinsic function allocated().

Assignment as allocation

One may combine allocation with initialisation in a number of ways including:

FORTRAN

  real, allocatable :: a(:)
  real, allocatable :: b(:)
  real, allocatable :: c(:)

  a = [ 1.0, 2.0, 3.0 ]          ! status now allocated
  allocate(b, source = a)        ! "sourced allocation"
  c = b(:)

Automatic reallocation is also possible for intrinsic assignments, e.g., following on from the above:

FORTRAN

  a = [ a(:), 4.0, 5.0, 6.0 ]    ! Append to the existing elements

Allocatable scalars are allowed and may be useful in some circumstances.

Zero-sized arrays


Formally, a zero-sized allocation is not well defined by malloc() in C. However, as Fortran arrays are objects, zero-sized arrays are possible:

FORTRAN

  integer :: a(0)      ! a zero-sized array
  integer :: b(0:0)    ! an array with one element b(0)

This can make it easier to write generic code which does not have to include conditionals to handle edge-cases where the array size might go to zero.

Two zero-sized arrays of the same rank may have different shapes, and so do not necessarilty conform (although a zero-sized array always conforms with a scalar, as usual). As a zero-sized array has no elements, it is always considered to be defined.

Exercise (5 minutes)


Challenge

Correcting array programs

Look at the accompanying programs to be found in the directory episodes/files/exercises/01-arrays within this repository:

problem1.f90       ! needs completing
problem2.f90       ! will fail to compile; correct the code
problem3.f90       ! will fail at run time; what is the problem?

These may be compiled with, e.g.,

BASH

$ ftn problem1.f90

The following print statements will perform the actions the comments ask for:

FORTRAN

print *, a([1, 2, 7])    ! => 1 2 7
print *, a(::2)          ! => 1 3 5 7 9
print *, b(:, [1, 3])    ! => 1 2 5 6

The compiler should highlight the source of the issue: i is undefined. The values in the array will still not be as requested. After fixing you should obtain the expected output

OUTPUT

Initial values    10.0000000       20.0000000       40.0000000

using the array constructor

real :: t(3) = [ (10.0*(2**(i-1)), i = 1, 3) ]

The program will SEGFAULT at runtime as a has not been allocated. Confirm this by copying the line to print Status to the point just before the array accesses are performed:

OUTPUT

Status  F

Allocating the array before accessing will allow the program to run correctly

OUTPUT

Status  F # Before allocation
Status  T # After allocation
Values    1.00000000       2.00000000       3.00000000

Alternatively, to perform assignment and allocation simultaneously, as described above, turn a(:) = ... into a = ....

Exercise (5 minutes)


Discussion

Array safety

As arrays are self-describing in Fortran, it is relatively easy for the compiler to analyse whether array accesses are valid, or within bounds. This can help debugging. Most compilers will have an option that instructs the compiler to inject additional code which checks bounds at run time. For the Cray Fortran compiler, this is -hbounds; for the GNU gfortran compiler, this is -fbounds-check.

The first example contains a fixed array element reference which is incorrect. This should be visible to the compiler at compile time:

BASH

$ ftn -hbounds bounds-compile-time.f90

The second example prompts for an array index at run time. This may or may not be out of bounds. Check what happens at run time if the value of 4 is entered.

BASH

$ ftn -hbounds bounds-run-time.f90

Check what happens if the tests are repeated using programs compiled without bounds checking. What are the possible dangers?

Key Points
  • Fortran supports both static- and dynamic-sized arrays
  • Fortran arrays are objects, allowing out of bounds accesses to be checked
  • The bounds of an array can be set by the programmer