The increased security is obtained not only through that each variable, which shall be used as a pointer, must be given an attribute POINTER, but also that all variables, that will be pointed to, must be given an attribute TARGET. An example explaining how to do this follows.
REAL, TARGET :: B(10,10) REAL, POINTER :: A(:,:) A => BThe matrix B has been specified completely, i.e. with the dimensions given explicitly. In addition, it has been stated that it can be the target of a pointer. The matrix A, which can be used as a pointer, has to be declared as a matrix, i.e. to be given a correct number of dimensions, a correct rank, but the extent for this is decided later, at the assignment (and in reality the assignment is a pointer-association) which is done with the symbols =>. Please note that the pointer assignment does not mean that the data in the matrix B is copied over to the matrix A (which would have taken relatively large resources), but it is merely a new address that is generated. To "move" data with the pointer concept will therefore be very efficient. As an alternative the pointer can become associated with the statement ALLOCATE, and be disassociated with DEALLOCATE, as in the following example.
ALLOCATE (A(5,5)) DEALLOCATE (A)There is also an internal function ASSOCIATED in order to investigate if a pointer is associated (and if it is associated with a certain target) and a statement NULLIFY in order to terminate the association.
IF ( ASSOCIATED (A) ) WRITE(*,*) ' A is associated ' IF ( ASSOCIATED (A, B) ) WRITE(*,*) ' A is associated with B' NULLIFY (A)Please remember that a pointer in Fortran 90 has both type and rank, and that these must agree with the corresponding target. This increases the security at the use of pointers, it is therefore not possible by mistake to let a pointer change values of variables of other (different) data types. The fact that you have to specify that a variable can be a target also increases both security and efficiency of the compilation.
Important application of pointers are lists and trees, and especially dynamic arrays.
REAL, TARGET :: A REAL, POINTER :: P, Q A = 3.1416 P => A Q => P A = 2.718 WRITE(*,*) QHere the value of Q equals 2.718 since both P and Q point towards the same variable A and that one has just changed its value from 3.1416 to 2.718. We now make a simple variation.
REAL, TARGET :: A, B REAL, POINTER :: P, Q A = 3.1416 B = 2.718 P => A Q => BNow both the values of A and P are equal to 3.1416 and the values of both B and Q are 2.718. If we now give the statement
Q = Pall four variables will get the value 3.1416, which means that an ordinary assignment of pointer variables has the same effect as the conventional assignment
B = AIf we instead give a pointer association
Q => Pthen the three variables A, P and Q all have the value 3.1416, while B contains the value 2.718. In the second case Q only points to the same variable as P while in the first case Q becomes the same as P, and the value addressed by Q becomes equal to the value addressed by P.
REAL, TARGET :: B(10,10) REAL, POINTER :: A(:), C(:) A => B(4,:) ! vector A becomes the fourth row C => B(:,4) ! and vector C becomes the fourth ! column of the matrix BIt is not necessary to take the whole section, you can take only a partial section. In the following example you can take a partial matrix WINDOW of a large matrix MATRIX.
REAL, TARGET :: MATRIX(100,100) REAL, POINTER :: WINDOW(:,:) INTEGER :: N1, N2, M1, M2 WINDOW => MATRIX(N1:M1, N2:M2)If you later wish to change a dimension of the partial matrix WINDOW you only need to make a new pointer association. Please note that the indices in WINDOW are not from N1 to M1 and from N2 to M2 but from 1 to M1-N1+1 and from 1 to M2-N2+1.
There does not exist arrays of pointers directly in Fortran 90, but you can construct such facilities by creating a new data type. An example is to store a lower (or left) triangular matrix with rows with varying length. First introduce a new data type ROW
TYPE ROW REAL, POINTER :: R(:) END TYPEand then specify the two lower triangular matrices V and L as vectors of rows with varying length
INTEGER :: N TYPE(ROW) :: V(N), L(N)after which you can allocate the matrix V as below (and in the corresponding way you can allocate the matrix L)
DO I = 1, N ALLOCATE (V(I)%R(1:I)) ! Various length of rows END DOThe statement
V = Lthen becomes equivalent with
V(I)%R => L(I)%Rfor all the components, i.e. all values of I. Please note that in this application there is no TARGET required.
An alternative method has however been suggested by Arie ten Cate, using a module with an ALLOCATEd and SAVEd array. An example is available.
We however use an INTERFACE with pointers in the main program and allocate, also using pointers, a vector in the subroutine. In this way we get a dynamically allocated vector.
PROGRAM MAIN_PROGRAM INTERFACE SUBROUTINE SUB(B) REAL, DIMENSION (:), POINTER :: B END SUBROUTINE SUB END INTERFACE REAL, DIMENSION (:), POINTER :: A CALL SUB(A) ! Now we can use the vector A. ! Its dimension was determined in the subroutine, ! the number of elements is available as SIZE(A). END PROGRAM MAIN_PROGRAM SUBROUTINE SUB(B) REAL, DIMENSION (:), POINTER :: B INTEGER M ! Now we can assign a value to M, for example ! through an input statement. ! When M has been assigned we can allocate B ! as a vector. ALLOCATE (B(M)) ! Now we can use the vector B. END SUBROUTINE SUBNote: The method above is even more useful for allocating matrices, see exercise 12.3.
(12.2) Specify two pointers, and let one of them point to a whole
vector and the other one point to the seventh element of the same
vector.
Solution.
(12.3) Use pointers to specify a matrix in such a way, that it is
given its size (its extent) in a subroutine but can be used in the
main program.
Solution.