Pointers

Yutaka Masuda

February 2020

Back to index.html.

Pointers

Pointer as an association to a variable

Motivation

In some cases, you may want to refer to a variable by a different name. A pointer is a separate variable to refer to the existing variable. It is useful to put an alternative name to the variable.

Pointing to a variable

For example, you have an integer array config(5), and it contains a set of configurations (e.g., the number of records) essential for your procedure. You can see the “number of records” in config(2), but 2 is a magic number, so it is awkward. One solution is to define a parameter like number_of_records=2 and to use config(number_of_records). It is meaningful, but the identifier is too long in some cases.

You can use a pointer to point to config(2). The pointer is a “shortcut” or an “alias” to the original variable. The following program declares a pointer, number_of_records, that is associated with the original variable, config(5).

integer,target :: config(5)=[10,20,30,40,50]
integer,pointer :: number_of_records

! The pointer is associated with the element.
number_of_records => a(2)

! Use a pointer like a variable
print *,number_of_records
        20

A variable to be referred (config) must have the target attribute on the declaration. A pointer has the same type as the target. The declaration of a pointer is the same as a variable except for the pointer attribute. To associate a pointer to the target variable, use =>. After the association, you can use the pointer like a variable.

pointer_variable => target_variable

Updating the pointer or the original variable

As seen above, a pointer is just pointing to the original value (number_of_records refers to config(2), which has the value, 20). Therefore, when you change the target variable, the pointer returns the updated value. Inversely, when you assign a value to the pointer, the target variable changes.

! update the original variable
config(2) = 99
print *,number_of_records

! assign a value to the pointer changing the original variable as well
number_of_records = 0
print *,config
          99
          10           0          30          40          50

Re-association of the pointer

You can immediately change the target of a pointer.

number_of_records => config(5)
print *,number_of_records
          50

Null pointer

When a pointer is not associated with anything, you must not use it. If you initialize the pointer (i.e., referring to the “null” target), use null() or nullify(). See the following usage.

! initialization in declaration
integer,pointer :: number_of_records => null()

! initialization in the main body
nullify(number_of_records)

You can use associated() to test whether a pointer is associated or not.

name description example
associated(p) test if pointer p is associated or not associated(number_of_records)

Summary

Pointer to a subarray

A pointer is useful to point to a subarray. See the following code.

integer,target :: config(5)=[10,20,30,40,50]
integer,pointer :: p(:) => null()

! case 1
p => config
print *,p

! case 2
p => config(2:4)
print *,p

! case 3
p => config(1:5:2)
print *,p
          10          20          30          40          50
          20          30          40
          10          30          50

The pointer to an array should have the same dimension, (:), as the target array. The pointer declaration looks like an allocatable array.

It is useful to refer to a submatrix. Here is an example define a pointer to (2:3,2:3) of the following matrix.

\[ \left[ \begin{array}{ccc} 1&4&7\\ 2&5&8\\ 3&6&9 \end{array} \right] \]

integer,target :: mat(3,3)
integer,pointer :: p(:,:)

mat = reshape([1,2,3,4,5,6,7,8,9],shape(mat))

! case 4
p => mat(2:3,2:3)
print *,p
           5           6           8           9

Using a pointer is to reach the target by indirect access. This fact penalizes the speed and the memory requirement to store the pointer. If the target is contiguous (cases 1 and 2), the speed loss is minimal, and no extra memory is needed. However, the target is not contiguous (cases 3 and 4); the penalty may be substantial. A best practice is: do not abuse a pointer to a non-contiguous array.

Pointer to free memory

The other usage of a pointer is to refer to free memory. It is the same as an allocatable array – you can allocate the pointer array before using it and deallocate it after the use. See the following code.

integer,pointer :: p(:)

allocate(p(3))
p(1:3) = [1,2,3]
print *,p
deallocate(p)

Here is the difference.

Difference Allocatable Pointer
Deallocation at the end of program unit Yes No
Allocating contiguous memory Yes No
Inquiring the allocation allocated() associated()

The allocatable array will be deallocated automatically, when you exit the program unit that has the declaration of the pointer. The pointer array is not released automatically. Instead, you should deallocate it by yourself; otherwise, it stays in memory until the main program stops. If you fail to do it, the occupied memory becomes garbage (i.e., memory leak).

The allocatable array can use the contiguous memory that can contribute to the performance. The pointer array does not guarantee the continuity, and it may affect the speed. Old programs used pointer arrays in a derived-type because Fortran 90/95 did not allow the derived-type to have allocatable arrays; the pointer array was allowed.

My recommendation is that you should always use the allocatable array to assign free memory because it is safer and better in performance.

Back to index.html.