Arrays may be declared in several different ways.
One may declare an array in a regular type statement, associating the array dimension with the variable name. For example,
REAL :: A(100)
This statement would declare the variable A to be an array of
type REAL with 100 separate memory units. The subscript
values range from 1 (default initial value in Fortran) to 100.
(In this style of declaration, one may omit the double colon.)
One may, alternatively, use a DIMENSION attribute, whose purpose is to assign arrays their dimensions. For example,
REAL, DIMENSION(1:100) :: A
This explicitly indicates that A is an array whose
single dimension starts at 1 and ends at 100 (inclusive).
There are other styles of declaring arrays dating to earlier versions of Fortran. Some of these involve using default typing for the arrays but using a DIMENSION statement to specify the size. The use of an separate DIMENSION statement is discouraged now (cf. section 18.10).
NOTES:
REAL B(-10:9)or
REAL, DIMENSION(-10:9) :: B
REAL :: D(4) = (/2.5,3.2,1.0,5.2/)
One can also use a implied DO-loop form when multiple
variables will be initialized to the same value, for example:
INTEGER :: A(100) = (/ (0 , I=1,100) /)
Note that the value to be "multiplied" along with the implied DO-loop
construction must be enclosed within its own set of parentheses
within the array constructor.
Although small arrays of higher dimensions cannot be initialized directly by an array constructor, they may be initialized by using the RESHAPE function (see section 8.11 below) with an array constructor as the SOURCE array.
Fortran-2003 permits the use of square brackets, [ and ], to enclose the values of an array constructor in place of (/ and /).
A = B(2) + B(3)*4.0NOTE: Currently, any INTEGER expression may be used. In older versions of Fortran, however, the subscript expression had to have a special form in which constant multipliers preceded variables and products preceded additions or subtractions.
SUM = 0.0 DO I=1,10 SUM = SUM + B(I) END DO
Undeclared arrays can lead to confusing error messages from some compilers. For example, suppose a programmer intended B to be an array and uses B in an assignment statement, e.g., A = 2*B(I). Suppose that, by oversight, B was not declared as an array. The compiler should detect an error at this point, and many compilers will give the error message: ``unknown FUNCTION B encountered.'' To understand the origin of this error message, one should examine the form of an array element, e.g., B(I). It is an identifier followed by another identifier within parentheses. Since this form is the same form used in a function call, e.g., COS(THETA) or SQRT(C), most compilers consider the first identifier (e.g., B) actually to be a function. The compiler then looks for the (non-existent) function in its lists of library and user-defined functions, and finding none by that name, gives an ``unknown function'' error message.
Another common error may occur when a programmer forgets to include the Fortran multiplication sign (*) between a variable and an expression surrounded by parentheses. For example, one might type
A = 2.0*B(I+J-3)rather than
A = 2.0*B*(I+J-3)and, since what was typed looks like a function call or an array, as in the previous case one may get an error message which seems to be unrelated to the actual error.
REAL NUM(3,3,5), NAMES(5:10,1:30)or
REAL, DIMENSION(1:3,1:3,1:5) :: NUM
REAL, DIMENSION(5:10,1:30) :: NAMES
In these examples, NUM is a three-dimensional array with
3×3×5 = 45 variables declared, and NAMES is a
two-dimensional array with 6×30 = 180 variables declared.
Fortran-90/95/2003 allows a maximum of 7 subscripts (very early versions allowed a maximum of 3 subscripts). Some local implementations, however, may allow more.
Two dimensional arrays are frequently used as tables to store information in rows and columns. The first subscript is usually associated with the row, and the second subscript is associated with the column. Two dimensional arrays are regularly used to store matrices used in mathematical problems.
Three dimensional arrays are often visualized as having rows, columns and levels, but no suitable visualization exists for four or higher dimension arrays.
Fortran stores arrays in what is called "column major" order. In other words, using the two-dimensional case as an example, the first column of the table (or matrix) is totally stored in consecutive memory locations before the second column is stored, and the second column before the third, etc.
For example, if L were a two dimension array dimensioned as follows,
INTEGER :: L(3,4)
it may be visualized as a
table or matrix with 3 rows and 4 columns, as follows:
L(1,1) L(1,2) L(1,3) L(1,4) L(2,1) L(2,2) L(2,3) L(2,4) L(3,1) L(3,2) L(3,3) L(3,4)The Fortran order of storage is L(1,1) followed by L(2,1) (which is the second element in the first column), followed by L(3,1) (which is the third and last element in the first column), followed by L(1,2) (which is the first element in the next column), followed by L(2,2), L(3,2), L(1,3), L(2,3), L(3,3), L(1,4), L(2,4), and finally L(3,4).
Fortran "column major" storage differs from the usual intuitive approach most people take in identifying the "next" element in a two-dimensional array (or matrix). The "human" order is "row major," i.e., the first row is stored (consecutively) before the next row. (This is the same "order" in which words in a paragraph are read in English.) In the previous example, the (human or row-major) order of the storage of elements of L would be L(1,1), L(1,2), L(1,3), L(1,4), L(2,1), L(2,2), L(2,3), L(2,4), L(3,1), L(3,2), L(3,3), and finally L(3,4). This is also the internal order used in several other computer languages, e.g., C/C++. This difference between the two orders can cause problems if one writes a Fortran subprogram which is to be used with a main program written in a different language and one wishes to pass arrays back and forth.
The standard rule of thumb used to decipher the order in which an array of any dimension is stored by Fortran is this: the first subscript varies the fastest. That is, in determining the changing of subscripts, the order is opposite from the order used on a digital clock or a mileage odometer in a car. For example, suppose A was declared as follows:
REAL A(3,4,2)then, in memory, the next location after the one containing A(1,3,1) would contain A(2,3,1), then A(3,3,1), then A(1,4,1). After A(3,4,1) would come A(1,1,2), and so on.
DO I=1,5,1 READ(5,101) A(I) 101 FORMAT(F10.5) END DOIf, however, one wanted to read more than one bit of information on one line, that fact needs to be indicated in the READ statement (and associated FORMAT statement).
Since, (following the standard rule) each READ statement (or each re-use in a loop of a READ statement) starts a new input line, if one wanted to read five numbers on one line, one would have to use only one READ statement and write something similar to the following:
READ(5,101) A(1),A(2),A(3),A(4),A(5) 101 FORMAT(5F10.5)One can simplify the notation by using an "implied DO-loop" construction as follows:
READ(5,101) (A(I),I=1,5) 101 FORMAT(5F10.5)Note that the DO-loop variable and its limits (with a step if desired) must be associated with a variable by means of parentheses. Essentially, the implied DO-loop expression is "expanded" to full form, and then the READ is executed.
If the array A is declared to be of dimension 5, one can omit the subscript and implied DO-loop entirely. For example, one can write:
READ(5,101) A 101 FORMAT(5F10.5)In this last case, (assuming that A was properly declared as an array) Fortran would know that A is an array rather than a scalar variable, and automatically "expand" A to its full dimension before executing the READ. Thus the three different examples given above would be equivalent in their actions!
NOTE: this same discussion also holds for output using WRITE statements.
Suppose A is dimensioned as REAL A(3,4). Then A has three "rows" and four "columns" if we think in terms of a table or matrix. Since Fortran stores the array in column order, this is the order which is used in "automatic" input or output (i.e., the third example in the previous section, the one without any subscripts). Therefore, if one omits the subscript, for example:
WRITE(*,101) Athen the order in which the elements of the two dimensional array would appear would be Fortran column order (rather than "human" row order). (Cf. the order for the elements of array L in section 8.7 above.)
To "force" row order, one needs to use implied DO-loops, for example,
WRITE(*,101) ((A(I,J),J=1,4),I=1,3)As with nested DO-loops, the nested implied DO-loops force the inner loop to be done completely (4 times) for each pass of the outer loop (cf. section 6.9). Since the inner loop controls the second subscript, the effect is that the second subscript varies faster than the first subscript, thereby producing row order.
The following example, with arrays, is similar to the example in section 4.6.
WRITE(6,102) (A(I),B(I),I=1,10) 102 FORMAT(1X,2F20.5)As in the example in section 4.6, the 102 FORMAT statement only provides for two numeric fields. The WRITE statement, however, in effect contains 20 variables which it wants to write out. Therefore, the formatting edit descriptors in the FORMAT get re-used 10 times, each time starting a new line. If, however, the edit descriptors were changed to allow three numbers per line, the output would consist of seven lines, with three variables per line for the first six lines, and two variables on the last line. The order of the variables would be the same, i.e., A(1), then B(1), then A(2), then B(2), then A(3), then B(3), etc.
Array identifiers may now be used in arithmetic expressions without any subscript when the same operation is to be performed on every element of the array. The presupposition, however, is that all arrays in such arithmetic expressions have the same number of dimensions and extent (size) of each dimension.
For example, if A, B and C are all dimensioned as follows,
REAL, DIMENSION(3,4) :: A,B,C
then the following is legitimate Fortran-90/95/2003 code:
C = A + B
This statement adds corresponding items in arrays A and B and stores the value in array C. To do this same operation in FORTRAN-77, one would need two nested DO-loops. Note that
C = A * B
multiplies corresponding elements in array A and array B
together and does not perform what is commonly called "matrix
multiplication." Matrix multiplication is provided by means of a
new intrinsic function in Fortran-90/95/2003 (discussed below in
section 8.13).
Other arithmetic operations on arrays also are permitted. For example, C = A * 3.0 indicates that every element in A is multiplied by 3.0 and the resulting value is stored as the corresponding element in C.
Intrinsic arithmetic functions may also be called on arrays, indicating that the operation is performed on every element in the array. For example, C = SQRT(A) invokes the SQRT function on every element in array A and stores the resulting values as the corresponding elements in C.
The action of the WHERE construct is as follows: For each element of the arrays in the construct, if the logical value determined by the mask evaluates to true, the statements within the structure are performed using the corresponding element of the arrays contained in those statements. (If the mask value evaluates to false, the statements in the ELSEWHERE section are performed, if this section exists.)
For example,
WHERE (A > 0.0)
B = SQRT(A)
ELSEWHERE
B = 0.0
ENDWHERE
will store in matrix B the square root of the values
stored in corresponding locations in matrix A, where those
values are positive (since that is what the mask expression,
A > 0.0, prescribes). For values that are zero or negative, a
zero is stored in the appropriate location in matrix B.
If there is no ELSEWHERE clause and only one assignment statement, the WHERE construct can be condensed to a single line, for example:
WHERE (A > 0.0) B = SQRT(A)
Fortran-95/2003 has extended the original Fortran-90 WHERE
statement to permit additional masks to be associated with any ELSEWHERE
statement contained in the structure. The mask must be of the
same shape as that used in the WHERE statement. If
there are multiple ELSEWHERE statements, only the last one may
be left without a mask. Fortran-95/2003 also permits the nesting
of WHERE statements and labeling as with DO
loops.
As an example, suppose that A, B and C are all square matrices of the same dimension. To compute, the matrix product of A and B and store the results in C, one would write:
C = MATMUL(A,B)
NOTE: The leading dimension of B must match the second dimension of A. But the second dimension of B may be 1 (or omitted) resulting in B being equivalent to a vector. In such a case, MATMUL(A,B) is equivalent to a matrix-vector product with a vector-valued result.
Any array to be allocated explicitly must be designated as such when declared. This is done by including the keyword ALLOCATABLE before the double colon in the type declaration and indicating the dimension by using colons in place of numbers. For example,
REAL, ALLOCATABLE :: A(:,:)
indicates that A is an allocatable array with two
dimensions. Then, before the array is actually used and assigned
values by the program segment, the code invokes
ALLOCATE( A(N,M) )
where N and M can be actual integer numbers or at
the least have been assigned values before that statement. When the
array is no longer needed, the code invokes
DEALLOCATE ( A )
Further details on these and on other array features and functions provided in Fortran-90/95/2003 can be found in specialized books.
This page is maintained by Dennis C. Smolarski, S.J.
dsmolarski@math.scu.edu
© Copyright 1998-2005 Dennis C. Smolarski, SJ, All rights reserved.
Last changed: 29 June 2005.