Skip to main content Skip to navigation

6. Arrays

1. Introduction

An array in f90 is a data structure that is used to store a collection of same-type objects. The general syntax for declaring an array is:

type, DIMENSION( extent ) :: array_name1, array_name2,...

The type give above is just the type you would use for any variable (eg real, integer, etc). The DIMENSION is a compulsory keyword. The extent is the range of entries/subscripts of the array elements. The general syntax for the element is:

start_integer : end_integer

These integers can be positive, negative or zero. You can neglect to give the first element, and f90 will assume this to take a value of 1. An array element can be referred to your code by the following syntax:

array_name1( integer expression )

where the integer expression can be as simple as an integer, or can be an expression to evaluate such as i + 1 , where i will be an integer variable.

Example:

For example, the array declaration:
 integer, DIMENSION( -2 : 2 ) :: a
declares an integer array, a, that has 5 elements: a(-2), a(-1), a(0), a(1) and a(2). If you had assigned an integer variable i = 2 , then you could refer to your elements as a(i-4), a(i-3), a(i-2), a(i-1) and a(i)

WARNING: You should always be careful to not address elements that are outside your delclared array - in the above example this would be like trying to access a(-3). If you tried to write something to a(-3) in this example, it would be written to random memory - and that can cause unpredicatable things to happen! (usually your program will crash). Note that if you make an error like this in your code, the compiler will not pick it up - so be careful!

2. Multidimensional arrays

Multidimensional arrays are possible in f90. For example, to store a matrix in f90, you can declare a two-dimensional array, e.g. below is a declaration for a 3 by 3 matrix:

real, DIMENSION( extent_1, extent_2 ) :: matrix_3by3

The first extent gives the range of rows in the matrix, the second extent gives the range of columns in the matrix.

Matrices in f90 in stored are in column-major order , as depicted below.

For example, if you tried to print out your array matrix_3by3 by just typing

print*,matrix_3by3

the elements would appear in output in the order given above.

Putting it into Practice:

Code up the statements below to see an example of how to assign values to matrix elements, and to print these elements out in column-major form.
program myarray
implicit none
integer :: i,j
integer, DIMENSION (1:3, 1:3) :: matrix_3by3

do i = 1, 3
  do j = 1, 3
   matrix_3by3(i,j) = i*j
  enddo
enddo

print*,matrix_3by3

end program myarray
Compile and run this code. Try writing some variations on this code.

As you have seen in the above example, you can refer to individual array elements as a specific position (eg, matrix_3by3(1,2) refers to the element in row1, column 2). However, in f90 you can also refer to sub-sections of the array, by giving the range of that subsection.

Example:

For example, the following references to matrix_3by3 mean..:
This refers to the entire first row of the matrix
  matrix_3by3(1,1:3) 
or
 matrix_3by3(1,:) 
This refers to the entire second column of the matrix
 matrix_3by3(1:3,2) 
or
 matrix_3by3(:,2)

You can also refer to elements in an array by specifying the stride. Unless specified, the stride will always be 1. Say you wanted to take every second element of matrix_3by3 (starting at element one), this could be done by specifying:

matrix_3by3(1::2)
or alternatively by typing
matrix_3by3(::2)

3. Array operations

In f90, you can apply whole-array operations. However, if more than one array is to be used in expressions, these arrays (or subsections thereof) must be of the same shape (ie have some number of rows and columns). The operators act on an element-by-element basis

Example:

An example of multiplying all elements of matrix_3by3 by a number, 2.5
 matrix_3by3 = matrix_3by3 * 2.5 
Initialising each element of matrix_3by3 to be set to 1.0
  matrix_3by3 = 1.0 
Example of an algebraic expression involving another matrix (same shape) called matrix_2
 matrix_3by3 = 3.0 * matrix_3by3 + (matrix_2)**2 
Example of multiplying 2 matrices. NOTE: this does not correspond with "matrix multiplication"!
 matrix_3by3 = matrix_3by3 * matrix_2 

In the last example above, the multiplication corresponds to

matrix_3by3(i,j) = matrix_3by3(i,j) * matrix2(i,j)

You can also apply intrinsic maths functions (such as trig functions, etc) to arrays in an element-by-element basis.

4. Array-specific functions

There is much much more to find out about manipulating arrays in f90 - in particular there exist many specific "array functions". Two you might find helpful are the functions dot_product (takes inner product of two linear arrays) and matmul (takes inner product of two matrices - ie, a "proper" matrix multiplication).

Putting it into Practice:

Code up the program below to see an example of how to use these array-specific operators.
program armanip
implicit none
integer :: i,j,c
integer, DIMENSION(1:3, 1:3) :: matrix_3by3,matrix_2,d
integer, DIMENSION(3) :: a,b

do i = 1, 3
  do j = 1, 3
   matrix_3by3(i,j) = i*j
   matrix_2(i,j) = 1.5 * j * (i+1)
  enddo
enddo

! create vector a from the first row of matrix_3by3
a = matrix_3by3(1,:)
! create vector b from the second row of matrix_2
b = matrix_2(2,:)

! take dot product of these two vectors
c = dot_product(a,b)
print*,c

! take the real matrix inner product of the two matrices
d = matmul(matrix_3by3,matrix_2)
print*,d

end program armanip
Compile and run this code. Try writing some variations on this code.

Given an array with a certain number of elements, you can "re-shape" this array into an array of another shape - eg, to turn a 9-element linear array into a 3by3 matrix

Putting it into Practice:

Code up the program below to see how the re-shape functionality works.
program shape
implicit none
integer :: i
integer, DIMENSION(1:3, 1:3) :: matrix_3by3
integer, DIMENSION(9) :: a

! assign elements of a to be 1 -> 9
a = (/ (i,i=1,9) /)
! reshape this array, a, into a 3by3 matrix
matrix_3by3 = reshape ( a, (/ 3,3 /) )

print*,matrix_3by3

end program shape
Compile and run this code. Try writing some variations on this code.

5. Allocatable arrays

One final area you may find helpful is that of allocatable arrays. Sometimes it's not convenient to have to decide on the size of an array at compile time. You can get flexibility by using an allocatable arrays - in this case you declare an array by specifying the rank (how many dimensions) only. You declaration must include the word allocatable . In the body of the code, you must allocate the memory for your array, and once you're done with it, free up that memory by de-allocating that memory.

Putting it into Practice:

Code up the program below to see how allocatable arrays work.
program dynamic
implicit none
integer :: i,j
integer, DIMENSION (:,:), allocatable :: matrix

print*,"Please enter the desired dimensions of your matrix"
read*,i,j

allocate ( matrix(0:i-1,0:j-1) )

matrix = 1.0
print*,matrix

deallocate ( matrix )

end program dynamic
Compile and run this code. Try writing some variations on this code.