SuivantPrec.Bas prec.BasNiv. sup.

9.6 Arrays as Arguments 

If the dummy argument of a procedure is an array then the actual argument can be either: The first form transfers the entire array; the second form, which just transfers a section starting at the specified element, is described in more detail further on.

The simplest, and most common, requirement is to make the entire contents of an array available in a procedure. If the actual argument arrays are always going to be the same size then the dummy arrays in the procedure can use fixed bounds. For example:
        SUBROUTINE DOT(X, Y, Z)
 *Computes the dot product of arrays X and Y of 100 elements
 * producing array Z of the same size.
        REAL X(100), Y(100), Z(100)
        DO 15, I = 1,100
           Z(I) = X(I) * Y(I)
 15     CONTINUE
        END
This procedure could be used within a program unit like this:
        PROGRAM PROD
        REAL A(100), B(100), C(100)
        READ(UNIT=*,FMT=*)A,B
                                                                  
                                                                  
        CALL DOT(A, B, C)
        WRITE(UNIT=*,FMT=*)C
        END
This is perfectly legitimate, if inflexible, since it will not work on arrays of any other size.

Adjustable Arrays 

A more satisfactory solution is to generalise the procedure so that it can be used on arrays of any size. This is done by using an adjustable arrays declaration. Here the operands in each dimension bound expression may include integer variables which are also arguments of the procedure (or members of a common block). The following example shows how this may be done:
        SUBROUTINE DOTPRO(NPTS, X, Y, Z)
        REAL X(NPTS), Y(NPTS), Z(NPTS)
        DO 15, I = 1,NPTS
 * etc.
In this case the calling sequence would be something like:       CALL DOTPRO(100, A, B, C) An adjustable array declaration is permitted only for arrays which are dummy arguments, since the actual array space has in this case already been allocated in the calling unit or at some higher level. The method can be extended in the obvious way to cover multi-dimensional arrays and those with upper and lower bounds, for example:
        SUBROUTINE MULTI(MAP, K1, L1, K2, L2, TRACE)
        DOUBLE PRECISION MAP(K1:L1, K2:L2)
        REAL TRACE(L1-K1+1)
The adjustable array mechanism can, of course, be used for arrays of any data type; an adjustable array can also be passed as an actual argument of a procedure with, if necessary, the array bounds passed on in parallel.

Each array bound of a dummy argument array may be an integer expression involving not only constants but also integer variables passed in to the procedure either as arguments or by means of a common block. The extent of each dimension of the array must not be less than one and must not be greater than the extent of the corresponding dimension of the actual argument array.

If any integer variable (or named constant) used in an array-bound expression has a name which does not imply integer type then the INTEGER statement which specifies its type must precede its use in a dimension-bound expression.

Assumed-size Arrays 

There may be circumstances in which it is impracticable to use either fixed or adjustable array declarations in a procedure because the actual size of the array is unknown when the procedure starts executing. In this case an assumed-size array is a viable alternative. These are also only permitted for dummy argument arrays of procedures, but here the array is, effectively, declared to be of unknown or indefinite size. For example:
        REAL FUNCTION ADDTWO(TABLE, ANGLE)
        REAL TABLE(*)
        N = MAX(1, NINT(SIN(ANGLE) * 500.0))
        ADDTWO = TABLE(N) + TABLE(N+1)
        END
Here the procedure only knows that array TABLE is one-dimensional with a lower-bound of one: that is all it needs to know to access the appropriate elements N and N+1. In executing the procedure it is our responsibility to ensure that the value of ANGLE will never result in an array subscript which is out of range. This is always a danger with assumed-size arrays. Because the compiler does not have any information about the upper-bound of an assumed-size array it cannot use any array-bound checking code even if it is normally able to do this. An assumed-size array can only have the upper-bound of its last dimension specified by an asterisk, all the other bounds (if any) must conform to the normal rules (or be adjustable using integer arguments).

An assumed size dummy argument array is specified with an asterisk as the upper bound of its last (or only) dimension. All the other dimension bounds, if any, must conform to normal rules for local arrays or adjustable arrays.

There is one important restriction on assumed size arrays: they cannot be used without subscripts in I/O statements, for example in the input list of a READ statement or the output list of a WRITE statement. This is because the compiler has no information about the total size of the array when compiling the procedure.

Array Sections 

The rules of Fortran require that the extent of an array (in each dimension if it is multi-dimensional) must be at least as large in the actual argument as in the dummy argument, but they do not require actual agreement of both lower and upper bounds. For example:
        PROGRAM CONFUS
        REAL X(-1:50), Y(10:1000)
        READ(UNIT=*,FMT=*) X, Y
        CALL OUTPUT(X)
        CALL OUTPUT(Y)
        END
 
        SUBROUTINE OUTPUT(ARRAY)
        REAL ARRAY(50)
        WRITE(UNIT=*,FMT=*) ARRAY
        END
The effect of this program will be to output the elements X(-1) to X(48) since X(48) corresponds to ARRAY(50), and then output Y(10) to Y(59) also. The subroutine will work similarly on a slice through a two-dimensional array:
        PROGRAM TWODIM
        REAL D(100,20)
 * ...
        NSLICE = 15
        CALL OUTPUT(D(1,NSLICE))
In this example the slice of the array from elements D(1,15) to D(50,15) will be written to the output file. In order to work out what is going to happen you need to know that Fortran arrays are stored with the first subscript most rapidly varying, and that the argument association operates as if the address of the specified element were transferred to the base address of the dummy argument array.

The use of an array element as an actual argument when the dummy argument is a complete array is a very misleading notation and the transfer of array sections should be avoided if at all possible.

Character Arrays  

When a dummy argument is a character array the passed-length mechanism can be used in the same way as for a character variable. Every element of the dummy array has the length that was passed in from the actual argument.

For example, a subroutine designed to sort an array of character strings into ascending order might start with specification statements like these:
        SUBROUTINE SORT(NELS, NAMES)
        INTEGER NELS
        CHARACTER NAMES(NELS)*(*)
Alternatively the actual argument can be a character variable or substring. In such cases it usually makes more sense not to use the passed-length mechanism. For example an actual argument declared:       CHARACTER*80 LINE could be passed to a subroutine which declared it as an array of four 20-character elements:
        SUBROUTINE SPLIT(LINE)
        CHARACTER LINE(4)*20
Although this is valid Fortran, it is not a very satisfactory programming technique to use a procedure call to alter the shape of an item so radically.

SuivantPrec.Bas prec.HautNiv. sup.