- Array declarations
- Use of arrays and array elements
- Initialising an array
- Input and output of arrays
- Multi-dimensional arrays

All our programs so far have required the storage of only a few values, and could therefore be written using only a few variables. For example, the average mark program of Figure 8 on page 18 required only variables for a mark, the total mark, the count of the marks and the average. When large numbers of values have to be stored, it becomes impracticaI or impossible to use different variables for them all. If the average mark program were rewritten to compute average marks for five subjects, we should require five variables, say MARK1 ... MARK5 for the marks, five variables for the totals, and five for the averages. This could be done, but the program would be rather repetitive. The situation is even worse if, after computing the averages, the program is required to print a list showing, for each student and subject, the student's mark and the difference between the mark and the average. This could conceivably be done if the number of students were given in advance, but the program would be extremely cumbersome. If, as in the example, the number of students is not given but determined by counting, the task is impossible, as there is no way of knowing how many variables will be required.

We need to store all the marks in order in a list or other structure to which we can apply a name, and refer to individual marks by a combination of the name and a number or numbers indicating the position of a mark in the list or structure.

In mathematics, an ordered list of items is called a **vector** of **dimension**
. If the vector is denoted by , the items, usually called the **components**
or **elements** of the vector, are denoted by .

FORTRAN uses a structure similar to a vector called an **array**. An array
` A` of dimension

A subscript can be any arithmetic expression which evaluates to an integer.
Thus, if `A, B`, and `C` are arrays, the following are valid ways
of writing an array element:

A(10) B(I+4) C(3*I+K)

Since an array is a list of variables, it obviously requires several words or other units of storage. Each array must therefore be declared in a statement which tells the compiler how many units to reserve for it. This can be done by including the array name in a type specification followed by its dimension in parentheses. For example:

INTEGER AGE(100),NUM(25),DEG

This reserves 100 words of storage for array `AGE`, 25 for array `NUM`,
and one word for the variable `DEG`. All three items are of type `INTEGER`.

Space can also be reserved for arrays by the ` DIMENSION`
statement, which reserves storage using a similar syntax, but includes no
information about type. Thus, if this method is used, the type is either
determined by the initial letter of the array or assigned by a separate type
specification. Therefore, the equivalent to the above using a

INTEGER AGE,DEG DIMENSION AGE(100),NUM(25)

(`NUM` is typed as `INTEGER` by default).

`DIMENSION` statements, like type specifications, are non-executable
and must be placed before the first executable statement.

Since a type specification can stipulate both type and dimension, there is
little point in using `DIMENSION` statements.

When this form of declaration is used in a type or DIMENSION statement the
upper and lower bounds for the subscript are 1 and the dimension respectively.
Thus, `AGE` in the above example may have any subscript from 1 to 100.
Arrays can also be declared to have subscripts with a lower bound other than 1
by using a second form of declaration in which the lower and upper bounds are
given, separated by a colon. For example:

REAL C(0:20) INTEGER ERROR(-10:10)

reserves 21 words of storage for each of the arrays `C` and `ERROR`
and stipulates that the subscripts of `C` range from 0 to 20 inclusive,
while those of `ERROR` range from -10 to 10.

Although the declaration stipulates bounds for the subscript, not all
compilers check that a subscript actually lies within the bounds. For example,
if `NUM` is declared as above to have a subscript from 1 to 25, a
reference to `NUM(30)`may not cause an error. The compiler may simply use
the 30th word of storage starting from the address of `NUM(1) `even
though this is outside the bounds of the array. This can cause unpredictable
results. Care should therefore be taken to make sure that your subscripts are
within their bounds.

Array elements can be used in the same way as variables, their advantage being that different elements of an array can be referenced by using a variable as a subscript and altering its value, for example by making it the control variable of a DO loop. This is illustrated in the following sections.

The array name without a subscript refers to the entire array and can be used only in a number of specific ways.

Values can be assigned to the elements of an array by assignment statements, e.g.

NUM(1) = 0

`NUM(2) = 5`

If all the elements are to have equal values, or if their values form a regular sequence, a DO loop can be used. Thus, if NUM and DIST are arrays of dimension 5:

DO 10, I = 1,5 NUM(I) = 0 10 CONTINUE

initialises all the elements of `NUM` to 0, while:

DO 10, I = 1,5 DIST(I) = 1.5*I 10 CONTINUE

assigns the values 1.5, 3.0, 4.5, 6.0 and 7.5 to `DIST(1),DIST(2),DIST(3)`,
`DIST(4)` and `DIST(5)` respectively.

The DATA statement is a non-executable statement used to initialise variables. It is particularly useful for initialising arrays. It has the form:

`DATA` *variable_list*/*constant_list*/ [,*variable_list*/*constant_list*/]
...

(The square brackets and ellipsis have their usual meaning.)

Each *variable_list* is a list of variables, and each *constant_list*
a list of constants, separated by commas in each case. Each *constant_list*
must contain the same number of items as the preceding *variable_list* and
corresponding items in sequence in the two lists must be of the same type.

The DATA statement assigns to each variable in each *variable_list* a
value equal to the corresponding constant in the corresponding *constant_list*.
For example:

DATA A,B,N/1.0,2.0,17/

assigns the values 1.0 and 2.0 respectively to the REAL variables `A`
and `B`, and 17 to the INTEGER variable `N`.

A constant may be repeated by preceding it by the number of repetitions required (an integer) and an asterisk. Thus:

DATA N1,N2,N3,N4/4*0/

assigns a value of zero to each of the variables `N1,N2,N3` and `N4`.

Items in a *variable_list* may be array elements. Thus, if `A` is
an array of dimension 20, the DATA statement:

DATA A(1),A(2),A(3),A(4)/4*0.0/,A(20)/-1.0/

assigns a value of zero to the first four elements, -1.0 to the last element, and leaves the remaining elements undefined.

When a large number of array elements have to be initialised, we can avoid
writing them all individually by using an **implied**** DO list**.

An implied DO list is used in a DATA statement or an input/output statement to generate a list of array elements. The simplest form of implied DO list is:

(*dlist, int=c1,c2*[,*c3*])

where *dlist* is a list of array elements separated by commas. The
expresssion: *int=c1,c2*[,*c3*] has a similar effect to the
expression: *var=e1,e2,*[,*e3*] in a DO loop, but *int* must be a
variable of type INTEGER, and *c1,c2* and *c3* must be constants or
expressions with constant operands. The **implied DO variable** *int* is
defined only in the implied DO list, and is distinct from any variable of the
same name used elsewhere.

The implied DO list expands *dlist* by repeating the list for each value
of *int* generated by the loop, evaluating the array subscripts each time.
Thus:

DATA (A(I),I=1,4)/4*0.0/,A(20)/-1.0/

has the same effect as the previous example.

A more complex use of an implied DO list is shown by the example:

DATA (A(I),A(I+1),I=1,19,3)/14*0.0/,(A(I),I=3,18,3)/6*1.0/

which assigns a value of zero to `A(1),A(2), A(4),A(5),` ... `A(19),A(20)`
and a value of 1.0 to every third element `A(3),A(6), ... A(18)` .

Finally, an entire array can be initialised by including its name, without a
subscript, in *variable_list* in a DATA statement. This is equivalent to a
list of all its elements in sequence. Thus, if `A` has dimension 20, all
the elements of `A` are initialised to zero by:

DATA A/20*0.0/

DATA statements can be placed anywhere in a program after any specifications.
In the interests of clarity, it is probably best to put them immediately before
the first executable statement. Wherever they may be, they cause initialisation *when
the program is loaded* (before execution begins). Therefore they can only be
used to *initialise* variables and not to re-assign values to them
throughout execution of the program. For this purpose, assignment statements or
READ statements must be used.

Array elements and array names can be used in input/output statements in much the same way as in DATA statements. Thus, input and output lists can include:

- array elements.
- array names (equivalent to all the elements in sequence).
- implied DO lists.

Implied DO lists in input/output statements differ in two respects from those in DATA statements:

- In output statements,
*dlist*can include*any*output list item. For example:

PRINT *, (A(I),'ABC', K, I=1,4)

will print the values of `A(1)`...`A(4)` followed in each case
by '`ABC`' and the value of `K`.

- The loop parameters need not be constants or constant expressions, but can include variables (INTEGER or REAL) provided that these have been assigned values, e.g.

N = 5 . PRINT *,(A(I),I=1,N)

In an input statement, the loop parameters can depend on values read before by the same statement, e.g.

READ *, N, (A(I),I=1,N)

If variables are used in this way, care should be taken to ensure that they lie within the subscript bounds of the array, as in the following example:

REAL A(20) . READ *, N IF (N.GE.1 .AND. N.LE.20) THEN READ *, (A(I),I=1,N) ELSE PRINT *, N, 'EXCEEDS SUBSCRIPT BOUNDS.' END IF

We can now return to the exam marks problem mentioned at the beginning of the chapter.

Write a program to read the marks of a class of students in five papers, and print, for each paper, the number of students sitting it and the average mark. The marks are to be read as a list of five marks in the same order for each student, with a negative mark if the student did not sit a paper. The end of the data is indicated by a dummy mark of 999.

The outline of the program is:

- Initialise the total mark for each of the five papers and a count of the number of students sitting it.
- Read five marks for the first student.
- While the first mark is not 999, repeat:
- For each of the five marks repeat:
- If the mark is not negative then:
- Increment the count of students sitting that paper.
- Add the mark to the total for that paper.

- If the mark is not negative then:
- Read five marks for the next student.

- For each of the five marks repeat:
- Repeat for each of five papers:
- If the count of students sitting the paper exceeds zero then:
- Compute the average mark for the paper.
- Print the number of the paper, the number of students sitting it, and the average mark.

- If the count of students sitting the paper exceeds zero then:

Otherwise

- Print a message: 'No students sat paper number'
*paper_number*

We shall use arrays `MARK`, `COUNT` and `TOTAL` to store
the five marks for a student, a count of students sitting each paper and the
total mark for each paper respectively. The program follows.

PROGRAM EXAM INTEGER MARK(5),TOTAL(5),COUNT(5) DATA COUNT/5*0/,TOTAL/5*0/ READ *,(MARK(I),I=1,5) 10 IF (MARK(1).NE.999) THEN DO 20, I=1,5 IF (MARK(I).GE.0) THEN COUNT(I) = COUNT(I)+1 TOTAL(I) = TOTAL(I)+MARK(I) END IF 20 CONTINUE READ *,(MARK(I),I=1,5) GOTO 10 END IF DO 30, I=1,5 IF (COUNT(I).GT.0) THEN AVMARK = 1.0*TOTAL(I)/COUNT(I) C MULTIPLY BY 1.0 TO CONVERT TO REAL AND AVOID TRUNCATION PRINT *,COUNT(I),' STUDENTS SAT PAPER NUMBER',I PRINT *,'THE AVERAGE MARK WAS', AVMARK ELSE PRINT *,'NO STUDENTS SAT PAPER NUMBER',I END IF 30 CONTINUE END

*Figure 12: Exam marks program*

One problem with this program is that if the last line of input consists of
the single terminating value of 999, the statement: `READ *,(MARK(I),I=1,5) `will
wait for another four values to be entered. This can be avoided by following 999
by a '/' character, which is a terminator causing the READ statement to ignore
the rest of the input list.

Suppose now that the exam marks program is to be altered to print a list of all the marks in each paper, with the differences between each mark and the average for the paper. This requires that all the marks should be stored. This could be done by making the dimension of MARK large enough to contain all the marks, and reserving the first five elements for the first student's marks, the next five for the second student's marks and so on. This would be rather awkward.

The problem could be dealt with more easily if we could add a second
subscript to the `MARK` array to represent the number of each student in
sequence. Our array could then be declared either by:

INTEGER MARK(5,100)

or by:

INTEGER MARK(100,5)

and would reserve enough space to store the marks of up to 100 students in 5 subjects.

In fact, FORTRAN arrays can have up to *seven* dimensions, so the above
declarations are valid. The subscript bounds are specified in the same way as
for one-dimensional arrays. For example:

REAL THREED(5,0:5,-10:10)

declares a three-dimensional array of type `REAL`, with subscript
bounds of 1...5, 0...5 and -10...10 in that order.

An array element must always be written with the number of subscripts indicated by the declaration.

When multi-dimensional array elements are used in an implied DO list,
multiple subscripts can be dealt with by including *nested implied DO lists*
in *dlist*, for example:

READ *, (A(J),(MARK(I,J),I=1,5),J=1,100)

Here, *dlist* contains two items, `A(J)` and the implied DO list `(MARK(I,J),I=,5)`
.This inner implied DO list is expanded once for each value of `J` in the
outer implied DO list. Thus the above READ statement reads values into the
elements of `A` and `MARK` in the order:

A(1), MARK(1,1), MARK(2,1),... MARK(5,1) A(2), MARK(1,2), MARK(2,2),... MARK(5,2) . A(100),MARK(1,100),MARK(2,100),...MARK(5,100)

The unsubscripted name of a multi-dimensional array can be used, like that of
a one-dimensional array, in input/output and DATA statements to refer to all its
elements, but it is essential to know their order. The elements are referenced *in
the order of their positions in the computer's memory*. For a one-dimensional
array, the elements occur, as we might expect, in increasing order of their
subscripts, but for multi-dimensional arrays, the ordering is less obvious. The
rule is that the elements are ordered with the first subscript increasing most
rapidly, then the next and so on, the last subscript increasing most slowly.
Thus if `MARK` is declared as:

INTEGER MARK(5,100)

its elements are ordered in memory as shown above, and the statement:

READ *,MARK

is equivalent to:

READ *, ((MARK(I,J),I=1,5),J=1,100)

Of course, the order could be altered by swapping the control variables in the inner and outer implied DO loops thus:

READ *, ((MARK(I,J),J=1,100),I=1,5)

We can use a two-dimensional array to solve the problem posed at the beginning of this section.

**Example 2:**

Write a program to read the marks of up to 100 students in five papers, and print, for each paper, the number of students sitting it, the average mark, and a list of the marks and their differences from the average. The marks are to be read as a list of five marks in the same order for each student, with a negative mark if the student did not sit a paper. The end of the data is indicated by a dummy mark of 999.

The outline is:

- Initialise the total mark for each of the five papers, a count of the number of students sitting it and a count of all the students.
- For up to 100 students, repeat:
- Read and store five marks
- If the first mark is 999, then continue from step 4.

Otherwise:

- Increment the count of all students.
- For each of the five marks repeat:
- If the mark is not negative then:
- Increment the count of students sitting that paper.
- Add the mark to the total for that paper.

- If the mark is not negative then:

- Read a mark. If it is not 999 then:
- Print a message: 'Marks entered for more than 100 students.'
- STOP

- Repeat for each of five papers:
- If the count of students sitting the paper exceeds zero then:
- Compute the average mark for the paper.
- Print the number of the paper, the number of students sitting it, and the average mark.
- Print a list of all the marks in that paper and their differences from the average for the paper.

- If the count of students sitting the paper exceeds zero then:

Otherwise

- Print a message: 'No students sat paper number'
*paper_number*

Step 4.1.3 can be further outlined as:

- For each student, repeat:

If his/her mark in the paper is not negative, then:

- Print the mark.
- Compute and print the difference between the mark and the average for the paper.

Since the marks are read five subjects at a time for each student, it is
convenient to store them in an array `MARK(5,100)`. The program follows:

PROGRAM EXAM2 INTEGER MARK(5,100),TOTAL(5),COUNT(5),ALL DATA COUNT/5*0/,TOTAL/5*0/,ALL/0/ DO 20, J=1,100 READ *,(MARK(I,J),I=1,5) IF (MARK(1,J).EQ.999) GOTO 30 ALL = ALL+1 DO 10, I=1,5 IF (MARK(I,J).GE.0) THEN COUNT(I) = COUNT(I)+1 TOTAL(I) = TOTAL(I)+MARK(I,J) END IF 10 CONTINUE 20 CONTINUE READ *,LAST IF (LAST.NE.999) THEN PRINT *,'MARKS ENTERED FOR MORE THAN 100 STUDENTS.' STOP END IF 30 DO 50, I=1,5 IF (COUNT(I).GT.0) THEN AVMARK = 1.0*TOTAL(I)/COUNT(I) C MULTIPLY BY 1.0 TO CONVERT TO REAL AND AVOID TRUNCATION PRINT *,COUNT(I),' STUDENTS SAT PAPER NUMBER',I PRINT *,'THE AVERAGE MARK WAS', AVMARK PRINT *,'MARKS AND THEIR DIFFERENCES FROM THE AVERAGE:' DO 40, J=1,ALL IF (MARK(I,J).GE.0)PRINT *,MARK(I,J),MARK(I,J)-AVMARK 40 CONTINUE ELSE PRINT *,'NO STUDENTS SAT PAPER NUMBER',I END IF 50 CONTINUE END

*Figure 13: Exam marks program (version 2)*

[Contents] [Previous] [Next] [Home]

**NDP77**

http://www.ndp77.net

webmaster Massimo F. ARENA

webmaster@ndp77.net

2004:02:14:17:30:17