• No results found

4.2 Using arrays

In document Fortran 95 (Page 63-67)

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

In document Fortran 95 (Page 63-67)