The Queen's University of Belfast
Parallel Computer Centre

[Next] [Previous] [Top]

4 Arrays


4.1 Terminology

4.1.1 Arrays and elements

Previous modules introduced simple data types, such as integer, real and character. In this module a structured data type called array is introduced.

An array is a collection of (scalar) data, all of the same type, whose individual elements are arranged in a regular pattern.

There are 3 possible types of arrays depending on the binding of an array to an amount of storage.

Static arrays: their size is fixed when the array is declared and can not be altered during execution. This is inflexible for certain circumstances (one has to re-entry the program, change the dimension(s) and re-compile) and wasteful in terms of storage space (since one might declare a very large array to avoid the previous problem)

Semi-dynamic arrays: the size of an array is determined after entering a subroutine and arrays can be created to match the exact size required but can only be used for a subroutine. In Fortran90 such arrays are called assumed-shape, and automatic arrays

Dynamic arrays : the size and therefore the amount of storage used by a dynamic array can be altered during execution. This is very flexible but slow run-time performance and lack of any bound checking during compilation. In Fortran90 such arrays are called allocatable arrays.

The reasons for using an array are:

This is an example of an array which contains integer numbers:

Assuming at the moment that the index (or subscript) starts at 1 then:

the first three elements are 5, 7, 13 with Indices of 1, 2 and 3 respectively and they form what is known as a section.

4.1.2 Array properties

The term Rank (or alternatively called dimension) refers to the number of subscripts needed to locate an element within an array. A scalar variable has a rank of zero.

Vector: An array with a rank of one is called a vector.

Matrix: An array with a rank of 2 or greater is called a matrix

Consider again the following array:

This array represents a vector since it is one-dimensional.

Consider the following array:

This array represents a matrix since it is two-dimensional.

The term Bounds refers to the lower subscript in each dimension. Hence the vector above has a lower bound of 1 and a higher bound of 8, whereas the above matrix has 1 and 2 for the first dimension and 1 and 4 for the second dimension.

The term Extent refers to the number of elements in a dimension. Hence the above vector has an extent of 8, whereas the above matrix has an extent of 2 and 4 in each dimension.

The term Shape is a vector containing the extents of an array. Hence the above vector has a shape of [8] whereas the matrix has a shape of [2,4].

The term Size refers to the total number of elements of an array, which simply is the product of extents. The size of an array may be zero but more about this later. Both vector and matrix above have a size of 8.

The term Conformance refers to arrays that have the same shape. This is a condition for array to array operations. Obviously an operation between an array and a scalar satisfies the conformance criterion. In such a case the scalar operation is repeated for all the elements of the array, as shown later.

4.2 Specifications

To specify an array the following attributes of the array must be known:

The name given to the array (e.g. Student_mark). The name given to the array is up to 31 alphanumeric characters including underscore but the first character must be a letter.

The type of the elements (e.g. integer). All elements must be of the same type and the type can be integer, real, logical, character, or derived.

The dimensions of the array (e.g. 1 dimension). Up to 7 dimensions are allowed

The lower and upper bounds for each dimension (e.g 1 and 8). Declaring the lower bound is optional. If the lower bound is not specified Fortran90 assumes that the index begins with 1. Notice that the type of the bounds is always integer. The alternate and equivalent forms used to declare an array are as follows:

type, DIMENSION(bound) [,attr] :: name

type [,attr] :: name (bound)

where [,attr] allows for the declaration of other type attributes, if required.

The following declarations are equivalent. Both declare an integer array a with 6 elements; an array b with 10 real elements and a logical 2-dimensional array named yes_no.

INTEGER, DIMENSION(6) :: a

REAL, DIMENSION(0:9) :: b

LOGICAL, DIMENSION(2,2) :: yes_no

INTEGER :: a(6)

REAL :: b(0:9)

LOGICAL :: yes_no(2,2)

Use the dimension attribute form when several arrays of the same bounds and type need to be declared. Use second form when several arrays of the same type but different bounds need to be declared. The choice is influenced by the style followed by the programmer but certain circumstances might dictate the use of one form rather than another.

A mixture of the two forms in the same program is allowed. Some further examples are shown below:

INTEGER, DIMENSION(8) :: x,y

REAL:: alpha(1:3), beta(4:9)

REAL, DIMENSION(0:5,12:45,6) :: data

CHARACTER(len=10) :: names(25)

The first example declares two arrays of the same dimension and type, therefore the dimension attribute form is employed. The second example declares two arrays of the same type but different dimension hence the array specification form is followed. For the third and fourth examples any of the two forms could have been used. The fourth example declares an array which has 25 elements with each element having a character string of size 10.

It is possible to include arrays as components of a derived data type and to declare arrays of derived data types, for example:

TYPE(point)

REAL :: position(3)

TYPE(point)

TYPE(point) :: object(10)

The type point is comprised of 3 real numbers, while the array object consists of 10 items of data, each consisting of 3 real numbers. Components are accessed as follows:

object(1)%position(1) !position 1 object 1

object(7)%position(2:) !positions 2 and 3 object 7

object(4)%position(:) !positions 1, 2 and 3 object 4

object(1:5)%position(1) !illegal object not array section.

Note that the array object cannot be used as an array section, although its components can (this is due to the unconventional storage requirements used by derived data types).

A third form is a mixture of the two above, as shown below:

type, DIMENSION(bound1) [,attr] :: aname, bname(bound2)

where aname takes the `default' number of elements, but bname takes another explicitly defined value. This is still legal but avoid using it due to the confusion that might arise.

4.3 Array Sections

One is able to access individual elements or sections rather than the whole array. Individual elements and sections of an array are uniquely identified through subscripts, one per rank.

4.3.1 Individual elements

To access a single element of an array the name of the array followed by an integer value enclosed in parentheses is needed. The integer value is the index of the element. For multi-dimensional arrays a list of integer values is required separated by a comma.

array (index, [...])

a(5) refers to the fifth element of the array

b(4,2) refers to the element at the intersection of the 4th row and 2nd column.

For above examples assume that lower bound is 1 and use the following declarations:

REAL, DIMENSION(8) ::a

INTEGER, DIMENSION(5,4) ::b

4.3.2 Sections

To access a section of an array you need the name of the array followed by two integer values separated by a colon enclosed in parentheses. The integer values represent the indices of the section required. For multi-dimensional arrays use a list of integer values separated by a comma.

array ([lower]:[upper]:[step], [...]) where lower and upper default to the declared dimensions and step defaults to 1.

a(3:5) refers to elements 3, 4, 5 of the array

a(1:5:2) refers to elements 1, 3, 5 of the array

b(1:3, 2:4) refers to elements from rows 1 to 3 and columns 2 to 4.

Using colon: This is a facility that enables us to access whole or parts of columns or rows. For example, b(:4) refers to all elements of the fourth column.

Using subscripts: For example, alpha(i,j) refers to the element at the intersection of ith row and jth column. Subscripts i,j are defined previously within the program.

Using expressions: For example, alpha(2*k) refers to an element whose position is the result of the multiplication. The result of an expression must be an integer within the declared bounds.

Using stride: For example, beta(3,1:7:2) refers to elements 1,3,5,7 of the third row., beta(1,2:11:2) refers to elements 2,4,6,8,10 of the first row. This is a valid statement despite that the upper bound of the second dimension is 10.

4.4 Vector Subscripts

This is a clever way providing a shorthand facility for accessing particular elements of a large array. Vector subscripts are integer expressions of rank 1 and take the form (/list/). Consider the following example.

REAL, DIMENSION(9) :: a

INTEGER, DIMENSION(3) :: random

random=(/6,3,8/)

a(random)=0.0

a((/7,8,9/))=1.2

Here two arrays have been declared, a with size 9 and random with size 3. The third statement assigns the values of 6, 3, and 8 to the three elements of random. Whatever value existed beforehand now has been overwritten. Hence,

random(1)=6

random(2)=3

random(3)=8

The fourth statement uses random as an array of indices and assigns the value of 0.0 to the array elements of a. Expanding the left hand side we get

a(random)=a(random(1),random(2),random(3))=a(6,3,8)

Hence the third, sixth and eighth element of a are the ones being overwritten with a zero value.

The fifth statement demonstrates an alternative use of the vector subscript. Hence the 7th, 8th and 9th element of the array are assigned the value of 1.2

Care must be taken not to duplicate values in a vector subscript when used in the LHS of an expression as demonstrated with the illegal fourth statement below.

REAL, DIMENSION(5) :: a

INTEGER, DIMENSION(3) :: list

list=(/2,3,2/)

a(list)=(/1.1, 1.2, 1.3/) !illegal element 2 set twice

4.5 Array storage

The physical storage: How an array is stored in memory depends on the computer implementation.

The array element ordering: It is wrong to assume that two elements of an array are next to each other BUT conceptualise a linear sequence of the array elements with the first index changing first.

Consider the following example:

REAL, DIMENSION(3, 5) :: a

4.6 Array Assignment

4.6.1 Whole array assignment

This is to be used when the elements of an array need to be assigned with the same value (scalar) or by coping the values of another array. In the former the scalar is broadcasted to all the elements of the array. In the latter case the operands in the array expression must be conformable

Consider the following example:

REAL, DIMENSION(100) :: a, b, c

REAL : d(10,10) = 0.0

b=2*a+4

a=2.0

c=b*a

c=d

The first assignment involves an array expression on the right hand side. Since a and b are conformable it is a valid statement. Each element of b takes the corresponding value of a multiplied by 2 and adding a 4 to the product.

The second assignment involves a scalar on the right hand side, hence there is automatic conformability. Each element of a takes the value of 2.

The third assignment involves an array product on the right hand side. Since a and b are conformable then their product can be evaluated. The product refers to element by element multiplication. The result is another array which is conformable with c therefore each element of c takes the product of the corresponding elements in a and b.

The fourth assignment is illegal because the two arrays are not conformable.

4.6.2 Array section assignment

In case that sections of an array have to be assigned certain values conforming array sections may appear in the expressions.

Consider the following example:

REAL, DIMENSION(10) :: alpha, beta

REAL :: gamma(20)

alpha(1:5)=2.0

alpha(1:10:2)=beta(1:5)/6

alpha(2:10)=alpha(1:9)

gamma(11:20)=beta

The first assignment simply assigns the value of 2 to the first 5 elements of alpha, the rest of the elements remain intact.

The second assignment involves two conformable array sections, hence it is a valid statement. The following assignments are made:

alpha(1)=beta(1)/6

alpha(3)=beta(2)/6

alpha(5)=beta(3)/6

alpha(7)=beta(4)/6

alpha(9)=beta(5)/6

The third assignment shows a powerful operation using arrays where values are shifted automatically and without the need of DO loops. Therefore, the 9 elements of alpha starting from the second element take the value of the first 9 element of alpha, so at the end of the process the first two elements of alpha have the same value.

The last assignment demonstrates another important concept. Whereas beta and gamma are not conformable the section used by gamma satisfies the criterion so it is a valid statement.

4.6.3 Elemental intrinsic procedures

Elemental procedures are specified for scalar arguments, but may take conforming array arguments.

Consider the following example:

REAL, num REAL, DIMENSION(3,3) :: a

INTEGER ::length(5)

CHARACTER(len=7) :: c(5)

x=SQRT(num)

a=SQRT(a)

length=LEN( TRIM(c) )

The first assignment is between two scalars and assigns the square root of num to x.

The second assignment involves the same elemental intrinsic procedure but with an array argument. Hence, every element of a is substituted by the square root of the existing value.

The third assignment finds the string length for each element of c and rejects any trailing blanks. Hence, if c(1) is `Alexis ` the command ignores the trailing blank.

4.7 Zero-sized arrays

Fortran 90 allows arrays to have zero size. This occurs when the lower bound is greater than the upper bound. A zero-sized array is useful because it has no element values, holds no data, but is valid and always defined. Zero-sized arrays allow the handling of certain situations without the need of extra code. As an example consider the following situation:

INTEGER :: a(5)=(/1,2,1,1,3/)

a(1:count(arr==1))=0

a(1:count(arr==1))=0

The first statement initialises a to 1 2 1 1 3 values.

The second statement arr(1:count(arr==1))=0 will change 1,2,1,1,3 to 0,0,0,1,3 since the original array had 3 elements with the value of 1.

The third statement arr(1:count(arr==4))=0 will do nothing because it is a zero-sized array (lower bound is 1, higher bound is 0 since there are no elements with the value of 4). Allowing for zero-sized arrays means that if the original array is empty or contains no elements with the required value the statement becomes a do nothing statement.

4.8 Initialising arrays

4.8.1 Constructors

This is to be used for 1-dimensional arrays that need to be assigned with various values. A constructor is a list enclosed in parentheses and back-slash. The general form is array = (/ list /) where list can be one of the following:

a list of values of the appropriate type:

INTEGER :: a(6)=(/1,2,3,6,7,8/)

variable expression(s)

REAL :: b(2)=(/SIN(x),COS(x)/)

array expression(s)

INTEGER :: c(5)=(/0,a(1:3),4/)

implied DO loops

REAL :: d(100)=(/REAL(i),i=1,100/)

The constructor can be used during declaration as shown above or in a separate statement but only the latter form can be employed to initialise an array with constant values.

4.8.2 Reshape

To be used for the initialisation or assignment of multi-dimensional arrays, i.e., arrays with rank greater than 1. It can be used on a declaration statement or in a separate statement. The format is

RESHAPE (list, shape [,PAD] [,ORDER])

where list is a 1-dimensional array or constructor containing the data, and shape a 1-dimensional array or vector subscript containing the new shape of the data.

The size of the array determines the dimension of the new array. The elements determine the extent of each dimension. Consider the following example:

INTEGER, DIMENSION(2,3) :: a

a=RESHAPE((/i,i=0,5/),(/3,2/))

The last statement will generate a rank 2 array with extents 3 and 2.

4.8.3 DATA statement

Use the DATA when other methods are tedious and/or impossible. For example for more than one array initialisation or for array section initialisation.

The format is:

DATA variable / list / ...

For example see following:

INTEGER :: a(4), b(2,2), c(10)

DATA a/4,3,2,1/

DATA a/4*0/

DATA b(1,:)/0,0/ DATA b(2,:)/1,1/

DATA (c(i),i=1,10,2/5*1/ DATA (c(i),i=2,10,2)/5*2/

The first DATA statement uses a list by value where the value for each array element is explicitly declared.

The second DATA statement uses a list by whole array where 4 is the size of the array and 0 is the required value which is repeated 4 times. Do not confuse this with the multiplication operator.

The third and fourth statements use a list by section where the first row takes 0 0 and the second row takes the values of 1 1.

The last two statements use a list by implied DO loops where the odd indexed elements are assigned the value 1 and the even indexed elements take the value of 2.

Remember that:

4.9 WHERE

To be used when the value of an element depends on the outcome of some condition. It takes a statement form or a construction form

The WHERE statement allows a single array assignment only if a logical condition is true. The syntax is as follows:

WHERE (condition) statement

Consider the following situation:

INTEGER :: a(2,3,4)

WHERE(a< 0) a=0

WHERE(a*3>10) a=999

The first WHERE statement means that all negative values of`a are set to zero, the non-negative values of a remain intact.

The second WHERE statement means that elements of a are set to 999 if the product is greater than ten.

The WHERE construct allows array assignment(s) only if a logical condition is true, and alternative array assignement(s) if false. The syntax is as follows:

WHERE (condition)

block1

[ELSEWHERE

block2]

ENDWHERE

Examine the following section of a program.

INTEGER :: b(8,8)

WHERE (b<=0)

b=0

ELSEWHERE

b=1/b

ENDWHERE

So all negative valued elements of `b' are set to zero and the rest take their reciprocal value.

4.10 Array intrinsic functions

Several intrinsic procedures are available in Fortran90. Their role is to save time and effort when programming. They can be divided into 7 sections for

A sample will now be presented.

4.10.1 Example of reduction

ALL (condition, [DIM])

determines whether all elements along a given dimension (DIM) satisfy the condition. The outcome is either a scalar (if dimension part is missing) or an array (if dimension part is declared) of logical type.

LOGICAL :: test, test2(2), test3(3)

REAL, DIMENSION(3,2) :: a

a = (/5,9,6,10,8,12/)

...

test=All(a>5)

test2=All(a>5, DIM=1) !false, true, true

test3=All(a>5, DIM=2) !false, true

The first statement gives false since the first element is equal to 5 and not greater.

The second statement gives [false,true,true] since the first element of the first row is equal to 5 and not greater, whereas both elements on the remaining two rows are greater than 5.

The third statement gives [false,true] since first element of the first column is equal to 5 and not greater, whereas all 3 elements on the remaining column are greater than 5.

4.10.2 Example of inquiry

SIZE(array, [DIM])

returns the extent of an array for the specified dimension (DIM). If the dimension part is missing it returns the total number of elements in the array.

REAL, DIMENSION(3,2) :: a

num=Size(a)

num=Size(a,DIM=1)

num=Size(a,DIM=2)

The first statement gives 6, the second gives 2, and the last gives 3.

4.10.3 Example of construction

SPREAD(array, DIM, NCOPIES)

replicates the given array by adding a dimension, where DIM stands for dimension and NCOPIES for number of copies.

REAL, DIMENSION(3) :: a=(/2,3,4/)

REAL, DIMENSION(3,3) :: b,c

b=SPREAD(a, DIM=1, NCOPIES=3)

c=SPREAD(a, DIM=2, NCOPIES=3)

The first SPREAD statement replicates array a three times on the row dimension. The second SPREAD statement replicates array a three times on the column dimension.

4.10.4 Example of location

MAXLOC(array, [mask])

determines the location of the first encountered element of the given array which has the maximum value and satisfies the optional mask.

REAL :: a(5) a=(/2,8,5,3,4/)

num = MAXLOC( a )

num = MAXLOC( a, MASK=a<5 )

num = MAXLOC( a(2:4) )

The first MAXLOC statement returns 2 since this is the position of the highest number on the list.

The second MAXLOC statement returns 5 since this is the position of the highest number on the list when numbers greater than 5 are excluded.

The third MAXLOC statement returns the value 1 since this is the position of the highest valued element in the array section. Note that it is worth remembering that elements in array section statements are renumbered with one as the lower bound in each dimension.

4.11 Exercises

  1. (a) A user enters the following elements to a (3x3) array: 1, 2, 5,8, 6, 7, 5, 0 , 0. What is the value of element(2,1); (3,2); (1,2); (2,3).

    (b) An array with rank 7 and extent of 5 in each dimension, how many elements does it have?

    (c) An array with rank 3 and extents of 10, 5 and 3, how many elements does it have?

  2. Given the following declarations:

    REAL, DIMENSION(1:10,1:20) :: a

    REAL, DIMENSION(10,-5:10) :: b

    REAL, DIMENSION(0:5,1:3,6:9) :: c

    REAL, DIMENSION(1:10,2:15) :: d

    What is the rank, size, bounds, and extents of a,b,c and d?

  3. Declare an array for representing a noughts and crosses board (a board of 3x3 squares, indicating an empty square with false, otherwise with true)

  4. Given the following declarations:

    REAL, DIMENSION(-1:5,3,8) :: alpha

    REAL, DIMENSION(-3:3,0:2,-7:0) :: beta

    Are the two arrays conformable?

  5. Given the following array declaration

    REAL: a(0:5,3)

    which of the following references are legal?

    a(2,3), a(6,2), a(0,3), a(5,6), a(0,0)

  6. What is the array element order of the following array?

    INTEGER, DIMENSION(-1:1,2,0:1) :: alpha

  7. Declare and initialise the array beta with the following elements

    5 6

    4 2

    0 5

  8. Declare and initialise the array gamma with the following element values: 2.1, 6.5, 4.3, 8.9, 12.5

  9. Declare and initialise the 2-rank array delta which has the following elements

    0 0 0 1

    0 0 1 1

    0 1 1 1

  10. Using a vector subscript declare an array zeta with 100 elements and place the value 8 to the 1st, 2nd, 10th, 34th, 99th and 100th element.

  11. The following array declarations are given:

    REAL, DIMENSION(50) :: alpha

    REAL, DIMENSION(60) :: beta

    which of the following statements are valid?

    alpha=beta

    alpha(3:32)=beta(1:60:2)

    alpha(10:50)=beta

    alpha(10:49)=beta(20:59)

    alpha=beta(10:59)

    alpha(1:50:2)=beta

    beta=alpha

    beta(1:50)=alpha

  12. Initialise an array of rank one and extend 10 with the values 1 to 10 using

    (a) a constructor with the list of values

    (b) a constructor with the Do Loop

  13. An array of rank one and extent 50 has been declared and needs to be initialised with the values of -1 (first element), 1 (last element) and 0 (rest of elements). Which of the following constructor structures are valid (if any)?

    alpha(/-1,(0,i=2,49),1/)

    alpha((/-1,(0,i=1,48),1/)

    alpha((/-1,(0,i=37,84),1/)

    alpha(/-1,48*0,1/)

  14. What are the values of the array delta which has been declared and initialised as follows:

    REAL, DIMENSION(2,2) ::delta=Reshape((/((10*i+j,i=1,2),j=1,2)/), (/2,2/))

  15. If the array beta has been declared as

    INTEGER, DIMENSION(10) :: beta

    what elements are referenced by each of the following statements?

    beta(2:8:3)

    beta(1:10)

    beta(3:5)

    beta(:9)

    beta(:)

    beta(::4)

    beta(3:10:0)

  16. If the array gamma has been declared as

    REAL, DIMENSION(3,4) : gamma

    what elements are referenced by each of the following statements?

    gamma(2,:)

    gamma(:,3)

    gamma(2,3:4)

    gamma(::2,:)

  17. If alpha has been declared and initialised as follows

    INTEGER, DIMENSION(-5:0) :: alpha=(/2,18,5,32,40,0/)

    what is the result of

    MAXLOC(alpha)

    MAXLOC(alpha,MASK=alpha/=40)

  18. Determine what the following array constructor does and then simplify the constructor: (/((A(i)+10.34,j=1,1000),i=1,1000) / )

  19. Write a WHERE statement which only changes the sign of the elements of array alpha that are negative.

  20. Write a WHERE statement which replicates every non-zero element of an array beta by its reciprocal and every zero element by 1.


[Next] [Previous] [Top]
All documents are the responsibility of, and copyright, © their authors and do not represent the views of The Parallel Computer Centre, nor of The Queen's University of Belfast.
Maintained by Alan Rea, email A.Rea@qub.ac.uk
Generated with CERN WebMaker