To implement the solution to printing 1000 numbers in reverse order, we could define 1000 variables, and use 1000 read and print statements:
double num1, num2, ... num1000 scanf("%lf", &num1); scanf("%lf", &num2); ... scanf("%lf", &num1000); printf("%f\n", num1000); ... printf("%f\n", num2); printf("%f\n", num1);
double precision :: num1, num2, ... num1000 read *, num1 read *, num2 ... read *, num1000 print *, num1000 ... print *, num2 print *, num1
We now have a program of 2000 lines + the overhead code framing out the program, defining the variables, etc. This is clearly more effort than we want to put into a program, and the program is not at all flexible. Where would we be if we needed to do the same for a billion numbers?
An array is a variable that holds multiple values of the same type. Each value in the array is distinguished from the others using an integer index, also known as a subscript. The term subscript comes from mathematics, where we might specify one element from of an array of values such as K0, K1, ... Kn.
In C, we make a variable into an array by providing the number of elements it contains in square brackets following the name. We then select an element by specifying the subscript in square brackets after the name. C subscripts always begin at 0 and end at the array size minus one.
#define LIST_SIZE 1000 double list[LIST_SIZE]; scanf("%lf", &list[0]); scanf("%lf", &list[1]); ... scanf("%lf", &list[999]); printf("%f\n", list[999]); ... printf("%f\n", list[1]); printf("%f\n", list[0]);
In Fortran, we make a variable into an array by providing the number of elements it contains in parentheses following the name. We then select an element by specifying the subscript in parentheses after the name. By default, Fortran subscripts begin at 1, but we can control this.
module constants integer, parameter :: LIST_SIZE=1000 end module double precision :: list(LIST_SIZE) read *, list(1) read *, list(2) ... read *, list(1000) print *, list(1000) ... print *, list(2) print *, list(1)
An array makes it much easier to allocate the space for 1000 double precision values, but we still have 2000 statements to read the list and print it backwards. Can we do better?
The only restriction on subscripts is that the must be integers. They may be constants, variables, or complicated expressions. As long as the value of the subscript is within the range of subscripts for the array, there is no problem.
Most commonly, subscripts are a simple variable which is controlled by a loop that traverses all valid subscripts for the array:
Variables used to subscript an array must have enough range. A Fortran integer(1) or C char variable have a maximum value of +127, so they cannot be used as subscripts for an array of 1000 elements. A Fortran integer (integer(4)) variable has a maximum value of 231-1 (a little over 2 billion), which is enough for most arrays. It is possible on modern computers to have arrays with more than 2 billion elements, so we may sometimes need to use integer(8).
The C header files define an unsigned integer type called
size_t
which has the same number of bits as a
memory address on the underlying hardware. Hence, it is
guaranteed to be able to handle an array of any size. This
data type should be used for virtually all array subscripts in C.
#define LIST_SIZE 1000 double list[LIST_SIZE]; size_t c; for (c = 0; c < LIST_SIZE; ++c) scanf("%lf", &list[c]); for (c = LIST_SIZE-1; c >= 0; --c) printf("%f", list[c]);
module constants integer, parameter :: LIST_SIZE=1000 end module double precision :: list(LIST_SIZE) integer :: index do index = 1, LIST_SIZE read *, list(index) enddo do index = LIST_SIZE, 1, -1 print *, list(index) enddo
In Fortran, if we want to define multiple arrays of the same size, we can use the dimension modifier instead of specifying the dimension for every array variable.
double precision, dimension(LIST_SIZE) :: list1, list2, list3
Fortran also allows the programmer to choose any starting and ending subscripts desired. The default starting subscript is 1, so the following is equivalent to the examples above:
double precision :: list(1:LIST_SIZE)
For some arrays, it may not make sense to use a starting subscript of one. For example, if an array contains the probability of a driver in the U.S. having an accident based on their age, then subscripts less than 15 would be useless, since people under are not allowed to drive.
We should also specify the array dimensions using named constants to make the program more readable and easier to modify.
module constants integer, parameter :: MIN_AGE=15, MAX_AGE=120 end module program insurance double precision :: accident_probability(MIN_AGE : MAX_AGE) integer :: age ... do age = MIN_AGE, MAX_AGE print *, accident_probability(age) enddo ... end program
#include <stdio.h> #include <sysexits.h> #define MIN_AGE 15 #define MAX_AGE 120 int main() { double accident_probability[MAX_AGE - MIN_AGE + 1]; size_t age; for (age = MIN_AGE; age <= MAX_AGE; ++age) printf("%f\n", accident_probability[age - MIN_AGE]); return EX_OK; }