Pointers and targets
Last updated on 2026-02-21 | Edit this page
Estimated time: 20 minutes
Overview
Questions
- How do I use a pointer to reference another variable?
- Can I alias variable names?
- Can I change the sizes of allocatable arrays?
Objectives
- Understand how to create pointers, targets, and how to associate the two to create references.
- Learn how to use an
associateblock to provide aliases to variables. - Learn how to efficiently reallocate storage for an allocatable array if its size needs to be changed.
Pointer attribute
A pointer may be declared by adding the pointer
attribute to the relevant data type, e.g.,
In this case we declare a pointer to integer p, which is
initialised to the special value null(). The pointer is
said to be unassociated. This is a different state to
undefined (i.e., without initialisation).
Note that pointer assignment uses => and not
=. A common cause of errors is to forget the
> if pointer assignment is intended.
It is important to be able to check that a given pointer is not
null(). This is done with the associated()
intrinsic; schematically,
If a pointer is not initialised as pointing to a target variable, it
should be initialised with null() to avoid undefined
behaviour when testing with associated(). Pointers may
otherwise be used in expressions and assignments in the usual way.
If one wishes to have a pointer to an array, the rank of the pointer should be the same as the target:
and so on.
Targets
A pointer may be associated with another variable of the appropriate type (which is not itself a pointer) by using the target attribute:
The pointer is now said to be associated with the target. We can now
perform operations on datum vicariously through
p. E.g., a standard assignment would be
FORTRAN
integer, target :: datum = 1
integer, pointer :: p => null()
...
p => datum ! pointer assignment
p = 2 ! normal assignment
leaves us with datum = 2. There is no dereferencing in
the C fashion; the data is moved as the result of the normal
assignment.
The target attribute is there to provide information to the compiler
about which variables may be, and which variables may not be, associated
with a pointer. This somewhat in the same spirit as the C
restrict qualifier.
Note that there is an optional target argument to the
associated() intrinsic, which allows the programmer to
inquire whether a pointer is associated with a specific target,
e.g.,
Exercise (2 minutes)
Associating a pointer
Try to compile the accompanying example1.f90, which is an erroneous version of the code above. See what compiler message you get (if any). Fix the problem.
Check you can use the associated() function to print out
the status of p before and after the pointer
assignment.
The p pointer can’t be associated with
datum as the latter doesn’t have the target
attribute; the compilation should fail with an error. If you add the
attribute, it should compile and run:
Check the associated() status of p along
these lines:
Pointers as aliases
One common use of pointers is to provide a temporary alias to another
variable (where no copying takes place). As a convenience, one can use
the associate construct, e.g.:
FORTRAN
real :: improbably_or_tediously_long_variable_name
...
associate(p => improbably_or_tediously_long_variable_name)
! ... lots of operations involving p ...
end associate
Note that there is no requirement here to have the
target attribute in the original declaration (and there’s
no explicit declaration of p). Any update to p
in the associate block will be reflected in the target on exit.
Multiple associations can be made in the same block; simply provide a comma separated list in the parentheses. Also of note is that the selector on the right hand side of the association can be either a variable or an expression.
Exercise (2 minutes)
Using an associate construct
Compile, and check the output of the accompanying code in example2.f90.
Pointers to establish storage
One common use of pointers is for linked data structures. For example, an entry in a linked list might be represented by the type
This sort of dynamic data structure requires that we establish or destroy storage as entries are added to the list, or removed from the list.
FORTRAN
subroutine my_list_add_node(head, datum)
! Insert new datum at head of list
type (my_node), pointer, intent(inout) :: head
integer, intent(in) :: datum
type (my_node), pointer :: pnode
allocate(pnode) ! assume no error
pnode%datum = datum
pnode%next => head
head => pnode
end subroutine my_list_add_node
In the subroutine, we can see the pointer pnode is
allocated. This dynamically creates a my_node variable to
contain the new datum. At the end of the procedure, the
pnode pointer is itself used as a target for the
head pointer.
Pointer or allocatable array?
The question may now arise: should you use pointers or allocatable
arrays? If you just want to establish storage for arrays, the answer is
almost certainly that you should use allocatable. An
allocatable array will almost certainly be held contiguously in memory,
whereas pointers are a more general data structure which may have to
accommodate a stride.
If an allocatable array is not appropriate, then a pointer may be required.
If you just require a temporary alias, the associate
construct is recommended.
Reallocating array storage
If one needs to increase (or decrease) the size of an existing
allocatable array, the move_alloc() intrinsic is useful.
E.g., if we have an integer rank one array
and establish storage of a given size, and some relevant initialisations, we may then wish to increase the size of it.
FORTRAN
integer :: nold
integer, dimension(:), allocatable :: itmp
nold = size(iorig)
allocate(itmp(2*nold)) ! double size; assume no error
itmp(1:nold) = iorig(1:nold) ! copy existing contents explicitly
call move_alloc(itmp, iorig)
! itmp deallocated, iorig now refers to the memory that had been itmp
This minimises the number of copies involved in re-assigning the original storage.
move_alloc() efficiency
A thought exercise. How many copies would be required if
move_alloc() was not available when enlarging the size of
an existing allocatable array?
If move_alloc() were not available, we would need to
make two copies rather than one. Analogously to the above example, we
would have to perform the following to double the storage in
iorig:
FORTRAN
integer :: nold
integer, dimension(:), allocatable :: itmp
nold = size(iorig)
allocate(itmp(nold)) ! allocate temporary storage for original data
itmp(:) = iorig(:) ! first copy from original storage into the temporary
deallocate(iorig) ! deallocate the original array
allocate(iorig(2*ndold)) ! and then reallocate at twice the size
iorig(1:nold) = itmp(:) ! second copy from the temporary into the new storage
deallocate(itmp) ! deallocate the temporary
Arrays of pointers
A small trick is required to arrange an array of pointers. Recall that
is a pointer to a rank one array, and not a rank one array of pointers. If one did want an array of such objects, it can be achieved by wrapping it in a type:
FORTRAN
type :: pointer_rr1
real, dimension(:), pointer :: p => null()
end type pointer_rr1
type (pointer_rr1), dimension(10) :: a
a(1)%p => null()
So a is a rank one array of the new type, each element
having the component p which is a pointer to a real rank
one type.
- Pointers are extremely useful for certain types of operations: they
provide a way to refer indirectly to other variables or names (they act
as an
_alias_), or can be used for establishing dynamic data structures. - Remember to always initialise a pointer, to
null()if necessary. - If a pointer is allocated, memory for its type is allocated and the pointer becomes associated.
- The
move_alloc()intrinsic function moves a memory allocation from one allocatable variable to another.