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*ZARRAY(2) is assigned 2.0*Y + 2*ZARRAY(3) is assigned 2.0*Y + 3*ZARRAY(4) is assigned 2.0*Y + 4*ZARRAY(5) is assigned 2.0*Y + 5*ZAn 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.