The value of every variable and array element is undefined at the start of
program execution unless it has been initialised in a DATA
statement. Undefined values may be used in executable statements only in
ways which cause them to become defined. There are a number of ways of
assigning a value to a variable or array element, including:
READ
statementDO
loop control variableWRITE
statementINQUIRE
statementUsing undefined variables in any other way can cause obscure errors which are fiendishly difficult to track down. Make sure your variables and arrays are properly initialised before you use them.
The equals sign =
acts as an assignment operator in
FORTRAN 77.
An arithmetic assignment statement has the form
symbolic name = arithmetic expression
where the symbolic name represents a variable or array element
of type COMPLEX
, DOUBLE PRECISION
,
INTEGER
or REAL
. If the arithmetic expression on
the right side of the =
operator has a different type from the
symbolic name on the left, type conversion is automatically applied to the
value of the arithmetic expression before it is applied to the variable or
array element.
Consider this program fragment where an array and a number of variables are declared and then initialised.
COMPLEX X DOUBLE PRECISION DUB INTEGER K,L REAL ARRAY(5),Y,Z Y = 119.7 Z = -0.45E+01 X = (Y,Z) DUB = 3.21D+08 K = Y DO 10, L = 1,5 ARRAY(L) = 2.0*Y + L*Z 10 CONTINUE
In this example, the REAL
variable Y
is assigned
the value 119.7 and the REAL
variable Z
is assigned
the value -4.5.
The COMPLEX
variable X
holds the value which can
be written mathematically as 119.7 - 4.5i.
The variable DUB
is given the value
3.21 × 108 using double precision rather than
single precision.
In the statement K = Y
, automatic type conversion
occurs since K
is type INTEGER
and Y
is type REAL
. However, the value assigned to K
is 119 and not 120. The REAL
value is
truncated, not rounded.
Finally, a DO
loop is used to initialise the
REAL
array:
ARRAY(1)
is assigned 2.0*Y + 1*Z
ARRAY(2)
is assigned 2.0*Y + 2*Z
ARRAY(3)
is assigned 2.0*Y + 3*Z
ARRAY(4)
is assigned 2.0*Y + 4*Z
ARRAY(5)
is assigned 2.0*Y + 5*Z
An character assignment statement has the form
symbolic name = character expression
where the symbolic name represents a variable, array element or
substring of type CHARACTER
.
CHARACTER BYE*20,GREET*5,HELLO*11 HELLO = 'Hello world' HELLO(7:11) = 'Earth'
In the first assignment statement, the string Hello world
is
assigned to the variable HELLO
and is stored as
Hello␣world
where
␣
is a blank or space.
The second assignment statement assigns the string Earth
to the
substring HELLO(7:11)
which means the variable
HELLO
now contains
Hello␣Earth
. The previously
defined values in positions 1 through 6 are unaffected. (If
HELLO
had not been previously defined, then those positions
would still be undefined.)
Now consider what happens if the expression on the right is longer than the variable on the left:
GREET = HELLO
In this statement, a character expression of length 11 is assigned to
a variable of length 5. When this occurs, the characters after position
5 are lost and the variable GREET
contains Hello
,
the first 5 characters of HELLO
.
Finally, examine the case where the expression on the right is shorter than the variable on the left:
BYE = 'Farewell'
When this happens, blanks ␣
are appended
(added to the right side). The variable BYE
is stored as
Farewell␣␣␣␣␣␣␣␣␣␣␣␣
.
An logical assignment statement has the form
symbolic name = logical expression
where the symbolic name represents a variable or array element
of type LOGICAL
.
CHARACTER*1 ANS LOGICAL DEBUG WRITE(*,*)'Do you wish to turn debugging on? Y/N' READ(*,10)ANS 10 FORMAT(A) DEBUG = ANS .EQ. 'Y' .OR. ANS .EQ. 'y'
The logical expression
ANS .EQ. 'Y' .OR. ANS .EQ. 'y'
evaluates to .TRUE.
only if ANS
contains either
Y
or y
. Once the expression is evaluated, the
value assigned to the LOGICAL
variable DEBUG
It is important to realise that the assignment operator =
is
not an 'equals sign' in the mathematical sense. In FORTRAN 77, the
assignment operator =
always assigns the value on the right
side of the operator to the symbolic name on the left side of the operator.
Thus, X = -13
is a valid arithmetic assignment
statement but -13 = X
is not, even though the
mathematical statements x = -13 and
-13 = x are equivalent.
A variable is simply a named memory location of a fixed type.
The value of a variable can be changed during the execution of the program. A
named constant, on the other hand, is fixed at compile time
and cannot be changed. The PARAMETER
statement is used to assign
a constant value to a symbolic name.
PARAMETER(cname1 = value1, cname2 = value2, …, cnamen = valuen)
Although the value of a FORTRAN 77 constant cannot be changed elsewhere
in the program, it can be used in other PARAMETER
statements as
well as in type declarations, DATA
statements and in calculations.
DOUBLE PRECISION DEG,PI,RAD,TWOPI PARAMETER(PI=3.141592653589793D0,TWOPI=2D0*PI) … RAD = DEG*PI/180D0
The value of the DOUBLE PRECISION
constant PI
is assigned in the PARAMETER
statement. The value of another
DOUBLE PRECISION
constant, TWOPI
, is also
assigned in the same PARAMETER
statement. This is done
simply by multiplying the already-defined constant PI
by
2D0
. Later in the program, the value of PI
is
used in an arithmetic expression.
INTEGER COLS,ROWS PARAMETER(ROWS=12,COLS=10) REAL MATRIX(ROWS,COLS),VECTOR(ROWS)
In this set of declarations, the constants COLS
and
ROWS
are declared to be of type INTEGER
before
being given the values in the following PARAMETER
statement.
After the constants have been defined, they can be used in the array
declarations on the next line. Using named constants as array bounds is
a common application in FORTRAN 77.
CHARACTER
constants are also possible. They can be declared
in the following manner:
CHARACTER*(*) cname PARAMETER(cname = 'string')
The length of the CHARACTER
constant cname is
automatically set to the length of the string in the
PARAMETER
statement. This only works with
CHARACTER
constants, not CHARACTER
variables which
must have the length explicitly declared. The CHARACTER*(*)
statement must precede the PARAMETER
statement.
CHARACTER*(*) ERRMSG PARAMETER(ERRMSG='Division by zero!')
In this example, the CHARACTER
constant ERRMSG
is
17 characters long and contains the string
Division by zero!
LOGICAL
constants can take the values .TRUE.
or
.FALSE.
LOGICAL DEBUG PARAMETER(DEBUG=.TRUE.) … IF (DEBUG) WRITE(*,*)'Entering first DO loop'
The LOGICAL
constant DEBUG
is set to
.TRUE.
and is used in an IF
statement later in
the program.
The DATA
statement is also used to initialise variables and
arrays. It takes the form
DATA var-list1 /value-list1/, var-list2 /value-list2/, …, var-listn /value-listn/
where var-list is a list of variable names, array names, substring
names and implied DO
lists, and value-list is a
list of literal or named constants, optionally preceded by a repeat-count and
an asterisk *
. The repeat-count is either an unsigned integer
value or a named constant.
The DATA
statement must follow the type specification statements
but can appear anywhere else in the program unit. By convention, they always
appear directly after the specification statements and before the executable
statements.
The important difference between the DATA
and
PARAMETER
statements is that the DATA
statement
specifies an initial value for a variable or array element which may be
subsequently changed during program execution. The value of a named constant
defined by a PARAMETER
statement may not be changed.
CHARACTER IFILE*20 INTEGER YEAR LOGICAL DEBUG DATA IFILE /'myinput.dat'/, YEAR /2013/, DEBUG /.FALSE./
In this example, the CHARACTER
variable is initialised to the
value myinput.dat␣␣␣␣␣␣␣␣␣
where ␣
is a blank or space. YEAR
takes the initial value 2013 and
DEBUG
is set to .FALSE.
An equivalent set of statements would be
CHARACTER IFILE*20 INTEGER YEAR LOGICAL DEBUG DATA IFILE,YEAR,DEBUG /'myinput.dat',2013,.FALSE./
or even
CHARACTER IFILE*20 INTEGER YEAR LOGICAL DEBUG DATA IFILE /'myinput.dat'/ DATA YEAR /2013/ DATA DEBUG /.FALSE./
although there is little to recommend this last version.
Either an entire array or just certain specified elements can be initialised
in a DATA
statement. If the entire array is being initialised,
then just the name of the array is used in the DATA
statement
but all of the elements must then be initialised.
LOGICAL OFFON(500) REAL MASS(500) DATA MASS /500*0.0/, OFFON /100*.TRUE.,400*.FALSE./
A repeat count of 500
is used to initialise all elements of the
array MASS
to 0.0
. The first 100 elements of the
array OFFON
are initialised to .TRUE.
and the
remaining 400 elements are set to .FALSE.
.
It is common practice to use named constants as array bounds and it is
permissible to use named constants (but not expressions involving named
constants) in DATA
statements.
INTEGER N1,N2,NTOTAL REAL ZERO PARAMETER(N1=100, N2=400, NTOTAL=N1+N2, ZERO=0.0) LOGICAL OFFON(NTOTAL) REAL MASS(NTOTAL) DATA MASS /NTOTAL*ZERO/, OFFON /N1*.TRUE.,N2*.FALSE./
This code accomplishes the same task as the previous snippet but uses
named constants in the DATA
statement.
If only a few elements of an array are to initialised, then each element must be listed separately.
INTEGER SMALL(10) DATA SMALL(2),SMALL(7) /4,-14/,
Only the second and seventh elements of the array SMALL
are
initialised. All of the rest of the array elements remain undefined.
An implied DO
loop allows selective access to array
elements and is used in I/O statements as
well as DATA
statements. The general form of the
implied DO
loop is
(data-list, loop-control-variable = initial-value, final-value, step-size)
The rules for the initial-value, final-value and
step-size are exactly the same as for a DO
loop.
An implied DO
loop may contain other
implied DO
loops nested within.
LOGICAL ODD(100) DATA (ODD(I),I=1,99,2) /50*.TRUE./, $ (ODD(I),I=2,100,2) /50*.FALSE./
The first line of the DATA
statement assigns the value
.TRUE.
to the array elements with odd-numbered indices whilst
the continuation line of the statement initialises the even-numbered array
elements with the value .FALSE.
Nested implied DO
loops are particularly useful when
initialising multi-dimensional arrays.
REAL UPTRI(10,10) DATA ((UPTRI(I,J),I=1,J),J=1,10) /55*1.0/
This DATA
statement initialises the upper triangular part of
the square matrix (two-dimensional array) UPTRI
to
1.0
. The rest of the matrix is undefined.
1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 |
1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | |
1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | ||
1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | |||
1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | ||||
1.0 | 1.0 | 1.0 | 1.0 | 1.0 | |||||
1.0 | 1.0 | 1.0 | 1.0 | ||||||
1.0 | 1.0 | 1.0 | |||||||
1.0 | 1.0 | ||||||||
1.0 |
In the main program unit, a nonexecutable DATA
statement has
the same effect as a bunch of assignment statements at the very beginning
of the program.
PROGRAM MAIN CHARACTER*20 NAME REAL DEC,MAG,RA DATA NAME,MAG,RA,DEC /'Alpha Centauri',-0.27,14.66,-60.84/
is equivalent to
PROGRAM MAIN CHARACTER*20 NAME REAL DEC,MAG,RA NAME = 'Alpha Centauri' MAG = -0.27 RA = 14.66 DEC = -60.84
However, this does not hold true in procedures. In an external function
or subroutine, the DATA
statement sets the values exactly
once, before the procedure is called, whereas assignment statements are
executed every time the procedure is called. This can be useful if there
are certain actions which need to happen the first time a procedure is
called but not subsequently.
SUBROUTINE ONEREC(UNITNO,RECORD) INTEGER UNITNO REAL RECORD LOGICAL OPENED DATA OPENED /.FALSE./ SAVE OPENED IF (.NOT. OPENED) THEN OPEN(UNITNO,FILE='inputfile.dat',STATUS='old',ERR=999) OPENED = .TRUE. END IF READ(UNITNO,*)RECORD RETURN 999 STOP 'Error opening file' END
The first time the subroutine is called, the LOGICAL
variable
OPENED
is initialised to .FALSE.
Therefore, the
logical expression .NOT. OPENED
is .TRUE.
on the first call and the block IF
statement is executed.
A file is opened and the variable OPENED
is reset to
.TRUE.
. Then RECORD
is read in from the opened
file and the subroutine returns to the calling program. On subsequent calls
to this subroutine, the logical expression in the block IF
will always be .FALSE.
and the subroutine will only read in
another value into RECORD
. This is because the SAVE
command preserves the value of OPENED
between calls to the
subroutine.
Note that DATA
cannot be used to initialise variables or arrays
which are dummy arguments in the procedure. DATA
cannot be used
to initialise values in blank COMMON
blocks but can be used in
the special BLOCK DATA
subroutine to initialise variables in
named COMMON
blocks.