Pointer

WARNING: Pointer in Fortran is DIFFERENT to pointer in C.

POINTER attribute and TARGET attribute

A pointer is what can point to a target, and a target is what can be pointed by a pointer. In Fortran, a pointer have the POINTER attribute, which should be specified by adding an `attr-spec` which is pointer, and a target which IS NOT A PROCEDURE have the TARGET attribute, which should be specified by adding an `attr-spec` which is target. There is nothing that can be both a pointer and a target in Fortran, which means there is no “pointer of pointer” in Fortran.

Pointer association status

A pointer has a pointer association status of associated, disassociated, or undefined. If a pointer is pointed to null(), it is disassociated, and if a pointer is pointed to something else, it is associated.

Pointer to scalar

We use => to make pointer assignment, and after that the pointer is pointed to the target. Then, if we make reference to the pointer, we will actually make reference to the target. We can’t and don’t need to get the value of the target which a pointer is pointing to by applying an operator to the pointer. If we change the value of the target, we will also change the value of the pointer, since the value of the pointer is actually the value of the target.

program main
    implicit none
    integer, pointer :: p
    integer, target :: a, b
    a = 1
    b = 2
    print *, 'a b = ', a, b
    p => a
    print *, 'p a b = ', p, a, b
    a = 3
    b = 4
    print *, 'p a b = ', p, a, b
    p => b
    print *, 'p a b = ', p, a, b
    a = 5
    b = 6
    print *, 'p a b = ', p, a, b
end program main

And also, If we change the value of the pointer, we will also change the value of the target, since the value of the pointer is actually the value of the target.

program main
    implicit none
    integer, pointer :: p
    integer, target :: a, b
    a = 1
    b = 2
    print *, 'a b = ', a, b
    p => a
    print *, 'p a b = ', p, a, b
    p = 3
    print *, 'p a b = ', p, a, b
    p => b
    print *, 'p a b = ', p, a, b
    p = 4
    print *, 'p a b = ', p, a, b
end program main

A pointer can not have the ALLOCATABLE attribute. However, A pointer can point to a target with the ALLOCATABLE attribute. In the following program, pointer p was pointed to allocatable character a, but when a was reassigned, a was deallocated and then reallocated, and when a was deallocated, p was not point to a again. We used associated(p, a) to check whether p was pointed to a in the following program.

program main
    implicit none
    character(:), pointer :: p
    character(:), allocatable, target :: a
    a = 'Hello, world!'
    p => a
    print *, p, a, associated(p, a)
    p(1:1) = 'h'
    print *, p, a, associated(p, a)
    a = 'Bye bye, world!'
    print *, p, a, associated(p, a)
end program main

However, in the following program, when p was assigned, a was NOT deallocated and then reallocated.

program main
    implicit none
    character(:), pointer :: p
    character(:), allocatable, target :: a
    a = 'Hello, world!'
    p => a
    print *, p, a, associated(p, a)
    p(1:1) = 'h'
    print *, p, a, associated(p, a)
    p = 'Bye bye, world!'
    print *, p, a, associated(p, a)
end program main

Pointer to array

First we should declare an array pointer. We must use :{, :}... to specify the rank but not the bounds of indexes of the array pointer, which makes the array pointer to be a “deferred-shape array”. Then we can simply make the array pointer pointed to an array target, and the bounds of indexes of the array pointer will be automatically determined by the array target.

program main
    implicit none
    integer, dimension(:, :), pointer :: p
    integer, dimension(3, 3), target :: a
    integer :: i
    a = reshape([(i, i = 1, 9)], [3, 3])
    p => a
    print *, p, a
    p = 0
    p(2, 2) = -1
    print *, p, a
end program main

We can redetermine the bounds of indexes of the array pointer. In the following program, the lower bounds of indexes of a are 1. We redetermine the lower bounds of indexes of p to be 0.

program main
    implicit none
    integer, dimension(:, :), pointer :: p
    integer, dimension(1:2, 1:2), target :: a
    a = 0
    p(0:, 0:) => a
    print *, p, a
    a(1, 1) = 1
    print *, p, a
    p(1, 1) = 2
    print *, p, a
end program main

An array pointer can only point to an array section.

program main
    implicit none
    integer, dimension(:, :), pointer :: p
    integer, dimension(3, 3), target :: a
    integer :: i
    a = reshape([(i, i = 1, 9)], [3, 3])
    p => a(:2, :2)
    print *, p, a
    p = 0
    print *, p, a
end program main

The rank of the array pointer and the array target can be different when the array target is a rank-one array, but at this time, we must explicitly determine the bounds of indexes of the array pointer, or the bounds can not be automatically determined. The elements of the array pointer are pointed to the elements of the array target in the sequence of the array elements.

program main
    implicit none
    integer, dimension(:, :), pointer :: p
    integer, dimension(2*5), target :: a
    integer :: i
    a = [(i, i = 1, 10)]
    p(1:2, 1:5) => a
    print *, p, a
    p(:, 3) = 0
    print *, p, a
end program main

The rank of the array pointer and the array target can also be different when the array pointer is a rank-one array, but at this time, we must explicitly determine the bounds of indexes of the array pointer, or the bounds can not be automatically determined. The elements of the array pointer are pointed to the elements of the array target in the sequence of the array elements.

program main
    implicit none
    integer, dimension(:), pointer :: p
    integer, dimension(3, 3), target :: a
    integer :: i
    a = reshape([(i, i = 1, 9)], [3, 3])
    p(1:6) => a(:, :2)
    print *, p, a
    p(3) = 0
    print *, p, a
end program main

However, at this time, the array target should be simply contiguous, therefore the following program is invalid.

program main
    implicit none
    integer, dimension(:), pointer :: p
    integer, dimension(3, 3), target :: a
    integer :: i
    a = reshape([(i, i = 1, 9)], [3, 3])
    p(1:6) => a(:2, :) ! Invalid, because `a(:2, :)` is not simply contiguous!
    print *, p, a
    p(3) = 0
    print *, p, a
end program main

Pointer to procedure

In the following program, we first made an abstract interface, and used that abstract interface to make the interface of p, ab2bc and ab2cb conformable. We used point to make p be a procedure pointer. We can’t and don’t need to use target to make ab2bc and ab2cb a target pointer, and they can be directly pointed.

program main
    implicit none
    abstract interface
        subroutine func_in_inout_out(arg_in, arg_inout, arg_out)
            integer, intent(in) :: arg_in
            integer, intent(inout) :: arg_inout
            integer, intent(out) :: arg_out
        end subroutine func_in_inout_out
    end interface
    procedure(func_in_inout_out), pointer :: p
    procedure(func_in_inout_out) :: ab2bc, ab2cb
    integer :: a, b, c
    a = 1
    b = 2
    c = 3
    p => ab2bc
    call p(a, b, c)
    print *, a, b, c
    a = 1
    b = 2
    c = 3
    p => ab2cb
    call p(a, b, c)
    print *, a, b, c
end program main

subroutine ab2bc(a, b, c)
    integer, intent(in) :: a
    integer, intent(inout) :: b
    integer, intent(out) :: c
    c = b
    b = a
end subroutine ab2bc

subroutine ab2cb(a, b, c)
    integer, intent(in) :: a
    integer, intent(inout) :: b
    integer, intent(out) :: c
    b = b
    c = a
end subroutine ab2cb