Introducing arrays
4.2 Using arrays
In the declaration statements given as examples in the above section, the array names are followed by bracketed lists of the extents of the arrays in each dimension. In assignment statements, or in expressions, a similar notation is used to specify a particular single element of an array, e.g.
surnames(12) = "Johnson"
assigns a value to the 12th element of surnames. It does not mean that surnames has rank 12. However, surnames must have rank of at least 12 in order for surnames (12) to exist. To take an example where an array element is on the right-hand side of an assignment statement,
x = 1.0 – SQRT(hash(98, 1, 14, 2))
takes one element out of the four-dimensional real array hash, and uses it to calculate x.
To refer to all the elements of an array it would be possible to use a construct like a DO loop (see Chapter 6), such as
Cuberoots: DO 1=1, 30 croots(i) = REAL(i)**(l.0/3.0) END DO Cuberoots
and this would set up a table of cube roots. But this sort of construction is generally not necessary: arrays really come into their own in Fortran because a reference to an array name by itself is equivalent to a reference to all the elements individually. For example, if x and y are one-dimensional arrays of size 12, then
x = y**2
As a rule, array assignment statements may refer to Fortran’s intrinsic functions, as in
this being equivalent to 12 scalar assignments and involving 12 calls to the function SQRT, if x and y both have size 12. Functions that can be used like this in array assignment statements are called “elemental”
functions because they operate on all the elements of the array that is given as their argument. Other valid statements would be, for example,
x = SQRT(x) and
x = y/z
The variables x, y and z here could be arrays of any shape, but their shapes must be the same. In the latter example, x(1) is set to y(1)/z(1), x(2) to y(2)/z(2), and so on.
An array assignment statement must have an array on the left-hand side with the same shape as the array (or array expression) on the right-hand side, but an exception to this rule is that we may have a scalar on the right-hand side, in which case all elements of the array are set equal to that same value. For example, going back to the first example of this section,
surnames = "Johnson"
would set all elements of the array called surnames to the same string “Johnson”. To show how an array might be used in a program, here is something equivalent to the program shown in Section 2.2:
PROGRAM Triangle REAL :: side(3)
WRITE (*,*) "This program calculates the area of a triangle."
WRITE (*,*) "Type in the lengths of the three sides:"
READ (*,*) side
WRITE (*,*) "Check: you have input the following lengths"
WRITE (*,*) side
s = 0.5 * SUM(side) ! Semiperimeter
areasq = s*PRODUCT(s-side) ! Square of the area IF (areasq<0.0) THEN
WRITE (*,*) "Error: that is not a real triangle"
ELSE
area = SQRT(areasq)
WRITE (*,*) "The area of the triangle is ", area END IF
END PROGRAM Triangle
This is no shorter than the earlier version of this program and it uses two intrinsic functions (SUM and PRODUCT) that will be explained at the end of this chapter. However, it illustrates how three variables (originally a, b and c) can be referred to under one name (side) so that the program reflects the mathematical symmetry of the problem. Note that READ and WRITE statements can be used with arrays, with the same effect as if each element of the array had been listed. So, the statement
WRITE (*,*) side is equivalent to
WRITE (*,*) side(1), side(2), side(3) On the other hand,
WRITE (*,*) sided) would only write the first element.
4.3
Array constructors
So far, we have looked at how variables are declared to be arrays, and at how arrays can be used in assignment statements and READ or WRITE statements. But how do we initially set values for the elements of an array? It is possible to set each element individually, as in
REAL :: x(3)
x(1) = 3.76; x(2) = –7.4; x(3) = 5.19
but for rank-1 arrays there is a simpler syntax known as an “array constructor” that looks like x = (/3.76, –7.4, 5.19/)
The array has its elements specified as a list between a (/ and a /). This notation can be used in an assignment statement, or it can be used when array variables (or named constants) are initially declared, as in
REAL :: x(3) = (/3.76, –7.4, 5.19/) or
INTEGER, PARAMETER :: months(12) = &
(/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)
(The PARAMETER attribute is explained in Chapter 8.) The list in an array constructor may include items that are themselves arrays, so
INTEGER :: u(3), v(3), w(3), uvw(9) u = (/1, 2, 3/)
v = 4 w = (/3,2,1/) uvw = (/u,v,w/)
has the effect of giving uvw the value (/1,2,3,4,4,4,3,2,1/)
Also, arrays within array constructors may themselves be array constructors, if you see what is meant. For example, uvw above could have been written
uvw = (/(/1,2,3/),v,(/3,2,1/)/)
Furthermore, a form of implied DO can be used in an array constructor. As an example, the table of cube roots given in the previous section is equivalent to
croots = (/ (REAL(i)**(1.0/3.0), i=1,30) /)
The meaning of this notation should be fairly clear even though the syntax is based on the idea of the DO loop described in Chapter 6. Within its own pair of brackets there is a structure comprising an expression, then a comma, then an index ranging between limits separated by another comma. The index name i is arbitrary, and the expression may be a function of the index. This structure creates an array element in the structure constructor for each value of the index over the range specified, i.e. 30 elements in the above case.
Another example is
ten_units = (/ (1.0, i=1,10) /) which is equivalent to
ten_units = 1.0
as long as ten_units was declared to be a rank-one array of size 10.
One should be aware that an array constructor cannot be used as the parent array in the specification of an array element or array section, i.e. something like
neat = (/1,2,3,4,4,4,5,6,7/)(7)
is an illegal statement and cannot be used to pick out the seventh element of the constructed array.
However, if miasma is the declared name of a nine-element rank-one integer array, then miasma = (/1,2,3,4,4,4,5,6,7/)
neat = miasma(7) does the trick.
Since an array constructor is a dimensional sequence of values, it can be used to construct only one-dimensional (rank-one) arrays. A one-one-dimensional array can be reshaped into a multione-dimensional array of the same size, using a special intrinsic function RESHAPE, but details of this are deferred until Chapter 9.
4.4