Pointers are variables with the POINTER attribute; they are not a distinct data type (and so no ``pointer arithmetic'' is possible):
REAL, POINTER :: varThey are conceptually a descriptor listing the attributes of the objects (targets) that the pointer may point to, and the address, if any, of a target. They have no associated storage until it is allocated or otherwise associated (by pointer assignment , see below):
ALLOCATE (var)and they are dereferenced automatically, so no special symbol is required. In
var = var + 2.3the value of the target of var is used and modified. Pointers cannot be transferred via I/O--the statement
WRITE *, varwrites the value of the target of var and not the pointer descriptor itself.
A pointer can point to other pointers, and hence to their targets , or to a static object that has the TARGET attribute:
REAL, POINTER :: object REAL, TARGET :: target_obj var => object ! pointer assignment var => target_objbut they are strongly typed:
INTEGER, POINTER :: int_var var => int_var ! illegal - types must matchand, similarly, for arrays the ranks as well as the type must agree.
A pointer can be a component of a derived data type :
TYPE entry ! type for sparse matrix REAL value INTEGER index TYPE(entry), POINTER :: next ! note recursion END TYPE entryand we can define the beginning of a linked chain of such entries:
TYPE(entry), POINTER :: chainAfter suitable allocations and definitions, the first two entries could be addressed as
chain%value chain%next%value chain%index chain%next%index chain%next chain%next%nextbut we would normally define additional pointers to point at, for instance, the first and current entries in the list.
A pointer's association status is one of
DEALLOCATE (p, q) ! for returning storage NULLIFY (p, q) ! for setting to 'null'
The intrinsic function ASSOCIATED can test the association status of a defined pointer:
IF (ASSOCIATED(pointer)) THENor between a defined pointer and a defined target (which may, itself, be a pointer):
IF (ASSOCIATED(pointer, target)) THEN
For intrinsic types we can ``sweep'' pointers over different sets of target data using the same code without any data movement. Given the matrix manipulation y = B C z, we can write the following code (although, in this case, the same result could be achieved more simply by other means):
REAL, TARGET :: b(10,10), c(10,10), r(10), s(10, z(10) REAL, POINTER :: a(:,:), x(:), y(:) INTEGER mult : DO mult = 1, 2 IF (mult == 1) THEN y => r ! no data movement a => c x => z ELSE y => s ! no data movement a => b x => r END IF y = MATMUL(a, x) ! common calculation END DOFor objects of derived data type we have to distinguish between pointer and normal assignment . In
TYPE(entry), POINTER :: first, current : first => currentthe assignment causes first to point at current, whereas
first = currentcauses current to overwrite first and is equivalent to
first%value = current%value first%index = current%index first%next => current%next
If an actual argument is a pointer then, if the dummy argument is also a pointer,
REAL, POINTER :: a(:,:) : ALLOCATE (a(80, 80)) : CALL sub(a) : SUBROUTINE sub(c) REAL c(:, :)
Function results may also have the POINTER attribute; this is useful if the result size depends on calculations performed in the function, as in
USE data_handler REAL x(100) REAL, POINTER :: y(:) : y => compact(x)where the module data_handler contains
FUNCTION compact(x) REAL, POINTER :: compact(:) REAL x(:) ! A procedure to remove duplicates from the array x INTEGER n : ! Find the number of distinct values, n ALLOCATE(compact(n)) : ! Copy the distinct values into compact END FUNCTION compactThe result can be used in an expression (but must be associated with a defined target).
These do not exist as such: given
TYPE(entry) :: rows(n)then
rows%next ! illegalwould be such an object, but with an irregular storage pattern. For this reason they are not allowed. However, we can achieve the same effect by defining a derived data type with a pointer as its sole component:
TYPE row REAL, POINTER :: r(:) END TYPEand then defining arrays of this data type:
TYPE(row) :: s(n), t(n)where the storage for the rows can be allocated by, for instance,
DO i = 1, n ALLOCATE (t(i)%r(1:i)) ! Allocate row i of length i END DOThe array assignment
s = tis then equivalent to the pointer assignments
s(i)%r => t(i)%rfor all components.
Given an array
REAL, TARGET :: table(100,100)that is frequently referenced with the fixed subscripts
table(m:n, p:q)these references may be replaced by
REAL, DIMENSION(:, :), POINTER :: window : window => table(m:n, p:q)The subscripts of window are 1:n-m+1, 1:q-p+1. Similarly, for
tar%u(as defined in chapter , page ), we can use, say,
taru => tar%uto point at all the u components of tar, and subscript it as
taru(1, 2)The subscripts are as those of tar itself. (This replaces yet more of EQUIVALENCE.)
The source code of an extended example of the use of pointers to support a data structure is here.