Pointers
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
- A pointer is an alias to a target variable.
- The target variable has the
target
attribute in the declaration. - The pointer is declared as a variable (with the
pointer
attribute) as the same type as the target. - The pointer is associated with the target by
=>
before using the pointer. - You can use a pointer as a regular variable.
- Changing the target variable changes the pointer value and vice versa.
- You can use
null()
ornullify()
to disassociate the pointer. Useassociate()
to test if the pointer is associated or not.
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.