Table of Contents Previous Chapter

TWO-DIMENSIONAL ARRAYS

Reference: Chapter 13 of Ellis, Philips, and Lahey

1. OVERVIEW

real :: a(100),b(100),c(100),i(25),k(10)

These are all one-dimensional arrays. It is also possible to have two, three, four, etc. dimensional arrays, for example:

# of dimensions f90 qty geometrical qty

0 a point

1 a(10) line

2 a(10,10) area (rectangle)

3 a(20,10,5) volume (cube)

Two-dimensional arrays are commonly used. Three and four-dimensional arrays are also used, but only occasionally. As the number of dimensions increases, the frequency of use of that type of array decreases. Fortran 90 allows up to seven dimensions in arrays. An example with two subscripts is as follows: real :: a(10,5)

reserves storage space for 50 real variables, and real :: area(0:10,0:5)

reserves space for 66 variables.

Again, you should notice that the default initial subscript for arrays is 1, not 0. If you want the array's initial value to be 0, you must explicity define it as in the previous example.

An example for the structure of a two-dimensional array, of dimension (10,4) is:

col. 1 col. 2 col. 3 col.4

row 1 a(1,1) a(1,2) a(1,3) a(1,4)

row 2 a(2,1) a(2,2) a(2,3) a(2,4)

row 3 a(3,1) a(3,2) a(3,3) a(3,4)

row 4 a(4,1) a(4,2) a(4,3) a(4,4)

.

.

.

row 10 a(10,1) a(10,2) a(10,3) a(10,4)

real :: a(#row, #col)

2. STORAGE

Arrays are stored contiguously (one after the other) in memory. This makes them easy for the CPU to fetch when doing computations. We have seen arrays which are one-dimensional (like a line). Storage in computers is linear. For example, a computer with 4 Megabytes of memory has addresses in memory corresponding to:

Two-dimensional arrays in Fortran are stored columnwise (first subscript varies most rapidly), first column 1, then column 2, etc. This will be very important in subroutines and in I/O (input/output).

Arrays are initialized with assignment statements, input statements, or data statements. If the name of an array is used without a subscript in I/O or data statements, the entire array is accessed in the order it is stored in memory (column order for a two dimensional array).

Since two subscripts are needed to use a two-dimensional array, most do loops used for reading or writing of arrays are nested do loops or implied do loops.

3. IMPLIED DO LOOP- IN I/O

Example:

  real :: b(8,10)
  .
  .
  .
  do i = 1,8
    print *, (b(i,j), j = 1,10)
  end do

The above code results in the array being printed as below. Note that the printing is different from the order in which the array is stored in memory.

Order:

b(1,1) b(1,2) . . . b(1,10)

b(2,1) b(2,2) . . . b(2,10)

b(3,1) b(3,2) . . . b(3,10)

b(4,1) b(4,2) . . . b(4,10)

.

.

b(8,1) b(8,2) . . . b(8,10)

(prints upside down)

to print forward:

  do i = 8, 1, -1
    print *, (b(i,j), j = 1, 10)
  end do

Finally, note that we sometimes include the row number in the output:

  do i = 8, 1, -1
    print *, 'row ', i, (b(i,j), j = 1, 10)
  end do

results in:

row 8 b(8,1) b(8,2) . . . b(8,10)

row 7 b(7,1) b(7,2) . . . b(7,10)

row 6 b(6,1) b(6,2) . . . b(6,10)

.

.

.

row 1 b(1,1) b(1,2) . . . b(1,10)

Allocatable Arrays

A new feature found in Fortran 90 that was not available in earlier versions is that of allocatable arrays. This allows the programmer to create temporary arrays whose size can be determined during the execution of the program.

There is a three-step procedure required in order to use allocatable arrays:

  1. The allocatable array is specified in a type declaration statement. This takes the format:
    
    real, allocatable, dimension(:,:) :: array1, array2,....
       OR
    real, allocatable :: array1(:,:), array2(:,:,:), .....
    

    Note: Since the size of the array is unknown at this time, the indices in the array declaration are represented by a single colon, using one colon for every dimension.

  2. Then, space can be dynamically allocated for the array in a separate allocation statement, after which the array may be used in the normal way. The format is:
    
    
    isize=20
    allocate (array1(isize,isize), array2(100,5,5))
       OR
    allocate (array1(isize,isize), array2(100,5,5), 
    stat=allocate_status)
    
    

    The advantage of allocating arrays is that the dimensions here can be variables. Thus, arrays can be made just large enough to accommodate data.

    Note: The "stat=allocate_status" element of the allocatable statement enables the processor to report on the success or failure of the allocation process, in a manner similar to that in which an iostat specifier reports the success or failure of an input/output statement.

  3. Finally, after the array has been used and is no longer required, the space for the elements can be deallocated by a deallocation statement. This takes the format:
deallocate (array1, array2) OR deallocate (array1, array2, stat=deallocate_status)

The following code fragment shows the usefulness of allocatable arrays.

subroutine space(n)
  implicit none
  integer :: n
  real, allocatable, dimension(:,:) :: a,b
!
  print *, 'enter n'
  read *, n
  allocate(a(2*n,6*n)        !Allocate space for a
   ! Do your calculations using a
   .
   .
   .
   .

  deallocate(a)        !Free space used by a
!
  allocate(b(3*n,4*n)        !Allocate space for b
   ! Do your calculations using b
   .
   .
   .
   .
  deallocate(b)        !Free space used by b
end subroutine space

Note in this code fragment that the space used by the arrays is 12n2. Had the option to use allocatable arrays not been available, we would have had to use at least 24n2 array spaces. In truth, we would most likely have had to over-dimension arrays a and b, since the code fragment implies that the incoming integer n is a variable. This ability to allocate and deallocate memory space is very useful when doing large problems on machines with limited memory.

Table of Contents Next Chapter