A debugger tool is used to search for errors in the programs.
A debugger program steps through the code and allows you to examine the values in the variables and other data objects during execution of the program.
It loads the source code and you are supposed to run the program within the debugger. Debuggers debug a program by −
Setting breakpoints,
Stepping through the source code,
Setting watch points.
Breakpoints specify where the program should stop, specifically after a critical line of code. Program executions after the variables are checked at a breakpoint.
Debugger programs also check the source code line by line.
Watch points are the points where the values of some variables are needed to be checked, particularly after a read or write operation.
The gdb Debugger
The gdb debugger, the GNU debugger comes with Linux operating system. For X windows system, gdb comes with a graphical interface and the program is named xxgdb.
Following table provides some commands in gdb −
Command
Purpose
break
Setting a breakpoint
run
Starts execution
cont
Continues execution
next
Executes only the next line of source code, without stepping into any function call
step
Execute the next line of source code by stepping into a function in case of a function call.
The dbx Debugger
There is another debugger, the dbx debugger, for Linux.
The following table provides some commands in dbx −
Command
Purpose
stop[var]
Sets a breakpoint when the value of variable var changes.
stop in [proc]
It stops execution when a procedure proc is entered
stop at [line]
It sets a breakpoint at a specified line.
run
Starts execution.
cont
Continues execution.
next
Executes only the next line of source code, without stepping into any function call.
step
Execute the next line of source code by stepping into a function in case of a function call.
Programming style is all about following some rules while developing programs. These good practices impart values like readability, and unambiguity into your program.
A good program should have the following characteristics −
Readability
Proper logical structure
Self-explanatory notes and comments
For example, if you make a comment like the following, it will not be of much help −
! loop from 1 to 10
do i = 1,10
However, if you are calculating binomial coefficient, and need this loop for nCr then a comment like this will be helpful −
! loop to calculate nCr
do i = 1,10
Indented code blocks to make various levels of code clear.
Self-checking codes to ensure there will be no numerical errors like division by zero, square root of a negative real number or logarithm of a negative real number.
Including codes that ensure variables do not take illegal or out of range values, i.e., input validation.
Not putting checks where it would be unnecessary and slows down the execution. For example −
real :: x
x = sin(y) + 1.0
if (x >= 0.0) then
z = sqrt(x)
end if
Clearly written code using appropriate algorithms.
Splitting the long expressions using the continuation marker ‘&’.
We have already discussed that, in older versions of Fortran, there were two real types: the default real type and double precision type.
However, Fortran 90/95 provides more control over the precision of real and integer data types through the kind specifie.
The Kind Attribute
Different kind of numbers are stored differently inside the computer. The kind attribute allows you to specify how a number is stored internally. For example,
real, kind = 2 :: a, b, c
real, kind = 4 :: e, f, g
integer, kind = 2 :: i, j, k
integer, kind = 3 :: l, m, n
In the above declaration, the real variables e, f and g have more precision than the real variables a, b and c. The integer variables l, m and n, can store larger values and have more digits for storage than the integer variables i, j and k. Although this is machine dependent.
program kindSpecifier
implicit none
real(kind = 4) :: a, b, c
real(kind = 8) :: e, f, g
integer(kind = 2) :: i, j, k
integer(kind = 4) :: l, m, n
integer :: kind_a, kind_i, kind_e, kind_l
kind_a = kind(a)
kind_i = kind(i)
kind_e = kind(e)
kind_l = kind(l)
print *,'default kind for real is', kind_a
print *,'default kind for int is', kind_i
print *,'extended kind for real is', kind_e
print *,'default kind for int is', kind_l
end program kindSpecifier
When you compile and execute the above program it produces the following result −
default kind for real is 4
default kind for int is 2
extended kind for real is 8
default kind for int is 4
Inquiring the Size of Variables
There are a number of intrinsic functions that allows you to interrogate the size of numbers.
For example, the bit_size(i) intrinsic function specifies the number of bits used for storage. For real numbers, the precision(x) intrinsic function, returns the number of decimal digits of precision, while the range(x) intrinsic function returns the decimal range of the exponent.
program getSize
implicit none
real (kind = 4) :: a
real (kind = 8) :: b
integer (kind = 2) :: i
integer (kind = 4) :: j
print *,'precision of real(4) =', precision(a)
print *,'precision of real(8) =', precision(b)
print *,'range of real(4) =', range(a)
print *,'range of real(8) =', range(b)
print *,'maximum exponent of real(4) =' , maxexponent(a)
print *,'maximum exponent of real(8) =' , maxexponent(b)
print *,'minimum exponent of real(4) =' , minexponent(a)
print *,'minimum exponent of real(8) =' , minexponent(b)
print *,'bits in integer(2) =' , bit_size(i)
print *,'bits in integer(4) =' , bit_size(j)
end program getSize
When you compile and execute the above program it produces the following result −
precision of real(4) = 6
precision of real(8) = 15
range of real(4) = 37
range of real(8) = 307
maximum exponent of real(4) = 128
maximum exponent of real(8) = 1024
minimum exponent of real(4) = -125
minimum exponent of real(8) = -1021
bits in integer(2) = 16
bits in integer(4) = 32
Obtaining the Kind Value
Fortran provides two more intrinsic functions to obtain the kind value for the required precision of integers and reals −
selected_int_kind (r)
selected_real_kind ([p, r])
The selected_real_kind function returns an integer that is the kind type parameter value necessary for a given decimal precision p and decimal exponent range r. The decimal precision is the number of significant digits, and the decimal exponent range specifies the smallest and largest representable number. The range is thus from 10-r to 10+r.
For example, selected_real_kind (p = 10, r = 99) returns the kind value needed for a precision of 10 decimal places, and a range of at least 10-99 to 10+99.
Intrinsic functions are some common and important functions that are provided as a part of the Fortran language. We have already discussed some of these functions in the Arrays, Characters and String chapters.
Intrinsic functions can be categorised as −
Numeric Functions
Mathematical Functions
Numeric Inquiry Functions
Floating-Point Manipulation Functions
Bit Manipulation Functions
Character Functions
Kind Functions
Logical Functions
Array Functions.
We have discussed the array functions in the Arrays chapter. In the following section we provide brief descriptions of all these functions from other categories.
In the function name column,
A represents any type of numeric variable
R represents a real or integer variable
X and Y represent real variables
Z represents complex variable
W represents real or complex variable
Numeric Functions
Sr.No
Function & Description
1
ABS (A)It returns the absolute value of A
2
AIMAG (Z)It returns the imaginary part of a complex number Z
3
AINT (A [, KIND])It truncates fractional part of A towards zero, returning a real, whole number.
4
ANINT (A [, KIND])It returns a real value, the nearest integer or whole number.
5
CEILING (A [, KIND])It returns the least integer greater than or equal to number A.
6
CMPLX (X [, Y, KIND])It converts the real variables X and Y to a complex number X+iY; if Y is absent, 0 is used.
7
CONJG (Z)It returns the complex conjugate of any complex number Z.
8
DBLE (A)It converts A to a double precision real number.
9
DIM (X, Y)It returns the positive difference of X and Y.
10
DPROD (X, Y)It returns the double precision real product of X and Y.
11
FLOOR (A [, KIND])It provides the greatest integer less than or equal to number A.
12
INT (A [, KIND])It converts a number (real or integer) to integer, truncating the real part towards zero.
13
MAX (A1, A2 [, A3,…])It returns the maximum value from the arguments, all being of same type.
14
MIN (A1, A2 [, A3,…])It returns the minimum value from the arguments, all being of same type.
15
MOD (A, P)It returns the remainder of A on division by P, both arguments being of the same type (A-INT(A/P)*P)
16
MODULO (A, P)It returns A modulo P: (A-FLOOR(A/P)*P)
17
NINT (A [, KIND])It returns the nearest integer of number A
18
REAL (A [, KIND])It Converts to real type
19
SIGN (A, B)It returns the absolute value of A multiplied by the sign of P. Basically it transfers the of sign of B to A.
Example
program numericFunctions
implicit none
! define constants
! define variables
real :: a, b
complex :: z
! values for a, b
a = 15.2345
b = -20.7689
ACOS (X)It returns the inverse cosine in the range (0, π), in radians.
2
ASIN (X)It returns the inverse sine in the range (-π/2, π/2), in radians.
3
ATAN (X)It returns the inverse tangent in the range (-π/2, π/2), in radians.
4
ATAN2 (Y, X)It returns the inverse tangent in the range (-π, π), in radians.
5
COS (X)It returns the cosine of argument in radians.
6
COSH (X)It returns the hyperbolic cosine of argument in radians.
7
EXP (X)It returns the exponential value of X.
8
LOG (X)It returns the natural logarithmic value of X.
9
LOG10 (X)It returns the common logarithmic (base 10) value of X.
10
SIN (X)It returns the sine of argument in radians.
11
SINH (X)It returns the hyperbolic sine of argument in radians.
12
SQRT (X)It returns square root of X.
13
TAN (X)It returns the tangent of argument in radians.
14
TANH (X)It returns the hyperbolic tangent of argument in radians.
Example
The following program computes the horizontal and vertical position x and y respectively of a projectile after a time, t −
Where, x = u t cos a and y = u t sin a - g t2 / 2
program projectileMotion
implicit none
! define constants
real, parameter :: g = 9.8
real, parameter :: pi = 3.1415927
!define variables
real :: a, t, u, x, y
!values for a, t, and u
a = 45.0
t = 20.0
u = 10.0
! convert angle to radians
a = a * pi / 180.0
x = u * cos(a) * t
y = u * sin(a) * t - 0.5 * g * t * t
write(*,*) 'x: ',x,' y: ',y
end program projectileMotion
When you compile and execute the above program, it produces the following result −
x: 141.421356 y: -1818.57861
Numeric Inquiry Functions
These functions work with a certain model of integer and floating-point arithmetic. The functions return properties of numbers of the same kind as the variable X, which can be real and in some cases integer.
Sr.No
Function & Description
1
DIGITS (X)It returns the number of significant digits of the model.
2
EPSILON (X)It returns the number that is almost negligible compared to one. In other words, it returns the smallest value such that REAL( 1.0, KIND(X)) + EPSILON(X) is not equal to REAL( 1.0, KIND(X)).
3
HUGE (X)It returns the largest number of the model
4
MAXEXPONENT (X)It returns the maximum exponent of the model
5
MINEXPONENT (X)It returns the minimum exponent of the model
6
PRECISION (X)It returns the decimal precision
7
RADIX (X)It returns the base of the model
8
RANGE (X)It returns the decimal exponent range
9
TINY (X)It returns the smallest positive number of the model
Floating-Point Manipulation Functions
Sr.No
Function & Description
1
EXPONENT (X)It returns the exponent part of a model number
2
FRACTION (X)It returns the fractional part of a number
3
NEAREST (X, S)It returns the nearest different processor number in given direction
4
RRSPACING (X)It returns the reciprocal of the relative spacing of model numbers near given number
5
SCALE (X, I)It multiplies a real by its base to an integer power
6
SET_EXPONENT (X, I)it returns the exponent part of a number
7
SPACING (X)It returns the absolute spacing of model numbers near given number
Bit Manipulation Functions
Sr.No
Function & Description
1
BIT_SIZE (I)It returns the number of bits of the model
2
BTEST (I, POS)Bit testing
3
IAND (I, J)Logical AND
4
IBCLR (I, POS)Clear bit
5
IBITS (I, POS, LEN)Bit extraction
6
IBSET (I, POS)Set bit
7
IEOR (I, J)Exclusive OR
8
IOR (I, J)Inclusive OR
9
ISHFT (I, SHIFT)Logical shift
10
ISHFTC (I, SHIFT [, SIZE])Circular shift
11
NOT (I)Logical complement
Character Functions
Sr.No
Function & Description
1
ACHAR (I)It returns the Ith character in the ASCII collating sequence.
2
ADJUSTL (STRING)It adjusts string left by removing any leading blanks and inserting trailing blanks
3
ADJUSTR (STRING)It adjusts string right by removing trailing blanks and inserting leading blanks.
4
CHAR (I [, KIND])It returns the Ith character in the machine specific collating sequence
5
IACHAR (C)It returns the position of the character in the ASCII collating sequence.
6
ICHAR (C)It returns the position of the character in the machine (processor) specific collating sequence.
7
INDEX (STRING, SUBSTRING [, BACK])It returns the leftmost (rightmost if BACK is .TRUE.) starting position of SUBSTRING within STRING.
8
LEN (STRING)It returns the length of a string.
9
LEN_TRIM (STRING)It returns the length of a string without trailing blank characters.
10
LGE (STRING_A, STRING_B)Lexically greater than or equal
11
LGT (STRING_A, STRING_B)Lexically greater than
12
LLE (STRING_A, STRING_B)Lexically less than or equal
13
LLT (STRING_A, STRING_B)Lexically less than
14
REPEAT (STRING, NCOPIES)Repeated concatenation
15
SCAN (STRING, SET [, BACK])It returns the index of the leftmost (rightmost if BACK is .TRUE.) character of STRING that belong to SET, or 0 if none belong.
16
TRIM (STRING)Removes trailing blank characters
17
VERIFY (STRING, SET [, BACK])Verifies the set of characters in a string
A module is like a package where you can keep your functions and subroutines, in case you are writing a very big program, or your functions or subroutines can be used in more than one program.
Modules provide you a way of splitting your programs between multiple files.
Modules are used for −
Packaging subprograms, data and interface blocks.
Defining global data that can be used by more than one routine.
Declaring variables that can be made available within any routines you choose.
Importing a module entirely, for use, into another program or subroutine.
Syntax of a Module
A module consists of two parts −
a specification part for statements declaration
a contains part for subroutine and function definitions
The general form of a module is −
module name
[contains [subroutine and function definitions] ] end module [name]
Using a Module into your Program
You can incorporate a module in a program or subroutine by the use statement −
use name
Please note that
You can add as many modules as needed, each will be in separate files and compiled separately.
A module can be used in various different programs.
A module can be used many times in the same program.
The variables declared in a module specification part, are global to the module.
The variables declared in a module become global variables in any program or routine where the module is used.
The use statement can appear in the main program, or any other subroutine or module which uses the routines or variables declared in a particular module.
module constants
implicit none
real, parameter :: pi = 3.1415926536
real, parameter :: e = 2.7182818285
contains
subroutine show_consts()
print*, "Pi = ", pi
print*, "e = ", e
end subroutine show_consts
end module constants
program module_example
use constants
implicit none
real :: x, ePowerx, area, radius
x = 2.0
radius = 7.0
ePowerx = e ** x
area = pi * radius**2
call show_consts()
print*, "e raised to the power of 2.0 = ", ePowerx
print*, "Area of a circle with radius 7.0 = ", area
end program module_example
When you compile and execute the above program, it produces the following result −
Pi = 3.14159274
e = 2.71828175
e raised to the power of 2.0 = 7.38905573
Area of a circle with radius 7.0 = 153.938049
Accessibility of Variables and Subroutines in a Module
By default, all the variables and subroutines in a module is made available to the program that is using the module code, by the use statement.
However, you can control the accessibility of module code using the private and public attributes. When you declare some variable or subroutine as private, it is not available outside the module.
Example
The following example illustrates the concept −
In the previous example, we had two module variables, e and pi. Let us make them private and observe the output −
module constants
implicit none
real, parameter,private :: pi = 3.1415926536
real, parameter, private :: e = 2.7182818285
contains
subroutine show_consts()
print*, "Pi = ", pi
print*, "e = ", e
end subroutine show_consts
end module constants
program module_example
use constants
implicit none
real :: x, ePowerx, area, radius
x = 2.0
radius = 7.0
ePowerx = e ** x
area = pi * radius**2
call show_consts()
print*, "e raised to the power of 2.0 = ", ePowerx
print*, "Area of a circle with radius 7.0 = ", area
end program module_example
When you compile and execute the above program, it gives the following error message −
ePowerx = e ** x
1
Error: Symbol 'e' at (1) has no IMPLICIT type
main.f95:19.13:
area = pi * radius**2
1
Error: Symbol 'pi' at (1) has no IMPLICIT type
Since e and pi, both are declared private, the program module_example cannot access these variables anymore.
However, other module subroutines can access them −
module constants
implicit none
real, parameter,private :: pi = 3.1415926536
real, parameter, private :: e = 2.7182818285
contains
subroutine show_consts()
print*, "Pi = ", pi
print*, "e = ", e
end subroutine show_consts
function ePowerx(x)result(ePx)
implicit none
real::x
real::ePx
ePx = e ** x
end function ePowerx
function areaCircle(r)result(a)
implicit none
real::r
real::a
a = pi * r**2
end function areaCircle
end module constants
program module_example
use constants
implicit none
call show_consts()
Print*, "e raised to the power of 2.0 = ", ePowerx(2.0)
print*, "Area of a circle with radius 7.0 = ", areaCircle(7.0)
end program module_example
When you compile and execute the above program, it produces the following result −
Pi = 3.14159274
e = 2.71828175
e raised to the power of 2.0 = 7.38905573
Area of a circle with radius 7.0 = 153.938049
A procedure is a group of statements that perform a well-defined task and can be invoked from your program. Information (or data) is passed to the calling program, to the procedure as arguments.
There are two types of procedures −
Functions
Subroutines
Function
A function is a procedure that returns a single quantity. A function should not modify its arguments.
The returned quantity is known as function value, and it is denoted by the function name.
Syntax
Syntax for a function is as follows −
function name(arg1, arg2, ....)
end function [name]
The following example demonstrates a function named area_of_circle. It calculates the area of a circle with radius r.
program calling_func
real :: a
a = area_of_circle(2.0)
Print *, "The area of a circle with radius 2.0 is"
Print *, a
end program calling_func
! this function computes the area of a circle with radius r
function area_of_circle (r)
! function result
implicit none
! dummy arguments
real :: area_of_circle
! local variables
real :: r
real :: pi
pi = 4 * atan (1.0)
area_of_circle = pi * r**2
end function area_of_circle
When you compile and execute the above program, it produces the following result −
The area of a circle with radius 2.0 is
12.5663710
Please note that −
You must specify implicit none in both the main program as well as the procedure.
The argument r in the called function is called dummy argument.
The result Option
If you want the returned value to be stored in some other name than the function name, you can use the result option.
You can specify the return variable name as −
function name(arg1, arg2, ....) result (return_var_name)
Subroutine
A subroutine does not return a value, however it can modify its arguments.
Syntax
subroutine name(arg1, arg2, ....)
end subroutine [name]
Calling a Subroutine
You need to invoke a subroutine using the call statement.
The following example demonstrates the definition and use of a subroutine swap, that changes the values of its arguments.
program calling_func
implicit none
real :: a, b
a = 2.0
b = 3.0
Print *, "Before calling swap"
Print *, "a = ", a
Print *, "b = ", b
call swap(a, b)
Print *, "After calling swap"
Print *, "a = ", a
Print *, "b = ", b
end program calling_func
subroutine swap(x, y)
implicit none
real :: x, y, temp
temp = x
x = y
y = temp
end subroutine swap
When you compile and execute the above program, it produces the following result −
Before calling swap
a = 2.00000000
b = 3.00000000
After calling swap
a = 3.00000000
b = 2.00000000
Specifying the Intent of the Arguments
The intent attribute allows you to specify the intention with which arguments are used in the procedure. The following table provides the values of the intent attribute −
program calling_func
implicit none
real :: x, y, z, disc
x = 1.0
y = 5.0
z = 2.0
call intent_example(x, y, z, disc)
Print *, "The value of the discriminant is"
Print *, disc
end program calling_func
subroutine intent_example (a, b, c, d)
implicit none
! dummy arguments
real, intent (in) :: a
real, intent (in) :: b
real, intent (in) :: c
real, intent (out) :: d
d = b * b - 4.0 * a * c
end subroutine intent_example
When you compile and execute the above program, it produces the following result −
The value of the discriminant is
17.0000000
Recursive Procedures
Recursion occurs when a programming languages allows you to call a function inside the same function. It is called recursive call of the function.
When a procedure calls itself, directly or indirectly, is called a recursive procedure. You should declare this type of procedures by preceding the word recursive before its declaration.
When a function is used recursively, the result option has to be used.
Following is an example, which calculates factorial for a given number using a recursive procedure −
program calling_func
implicit none
integer :: i, f
i = 15
Print *, "The value of factorial 15 is"
f = myfactorial(15)
Print *, f
end program calling_func
! computes the factorial of n (n!)
recursive function myfactorial (n) result (fac)
! function result
implicit none
! dummy arguments
integer :: fac
integer, intent (in) :: n
select case (n)
case (0:1)
fac = 1
case default
fac = n * myfactorial (n-1)
end select
end function myfactorial
Internal Procedures
When a procedure is contained within a program, it is called the internal procedure of the program. The syntax for containing an internal procedure is as follows −
program program_name
implicit none
! type declaration statements
! executable statements
. . .
contains
! internal procedures
. . .
end program program_name
The following example demonstrates the concept −
program mainprog
implicit none
real :: a, b
a = 2.0
b = 3.0
Print *, "Before calling swap"
Print *, "a = ", a
Print *, "b = ", b
call swap(a, b)
Print *, "After calling swap"
Print *, "a = ", a
Print *, "b = ", b
contains
subroutine swap(x, y)
real :: x, y, temp
temp = x
x = y
y = temp
end subroutine swap
end program mainprog
When you compile and execute the above program, it produces the following result −
Before calling swap
a = 2.00000000
b = 3.00000000
After calling swap
a = 3.00000000
b = 2.00000000
In the last chapter, you have seen how to read data from, and write data to the terminal. In this chapter you will study file input and output functionalities provided by Fortran.
You can read and write to one or more files. The OPEN, WRITE, READ and CLOSE statements allow you to achieve this.
Opening and Closing Files
Before using a file you must open the file. The open command is used to open files for reading or writing. The simplest form of the command is −
open (unit = number, file = "name").
However, the open statement may have a general form −
open (list-of-specifiers)
The following table describes the most commonly used specifiers −
Sr.No
Specifier & Description
1
[UNIT=] uThe unit number u could be any number in the range 9-99 and it indicates the file, you may choose any number but every open file in the program must have a unique number
2
IOSTAT= iosIt is the I/O status identifier and should be an integer variable. If the open statement is successful then the ios value returned is zero else a non-zero value.
3
ERR = errIt is a label to which the control jumps in case of any error.
4
FILE = fnameFile name, a character string.
5
STATUS = staIt shows the prior status of the file. A character string and can have one of the three values NEW, OLD or SCRATCH. A scratch file is created and deleted when closed or the program ends.
6
ACCESS = accIt is the file access mode. Can have either of the two values, SEQUENTIAL or DIRECT. The default is SEQUENTIAL.
7
FORM = frmIt gives the formatting status of the file. Can have either of the two values FORMATTED or UNFORMATTED. The default is UNFORMATTED
8
RECL = rlIt specifies the length of each record in a direct access file.
After the file has been opened, it is accessed by read and write statements. Once done, it should be closed using the close statement.
The close statement has the following syntax −
close ([UNIT = ]u[,IOSTAT = ios,ERR = err,STATUS = sta])
Please note that the parameters in brackets are optional.
Example
This example demonstrates opening a new file for writing some data into the file.
program outputdata
implicit none
real, dimension(100) :: x, y
real, dimension(100) :: p, q
integer :: i
! data
do i=1,100
x(i) = i * 0.1
y(i) = sin(x(i)) * (1-cos(x(i)/3.0))
end do
! output data into a file
open(1, file = 'data1.dat', status = 'new')
do i=1,100
write(1,*) x(i), y(i)
end do
close(1)
end program outputdata
When the above code is compiled and executed, it creates the file data1.dat and writes the x and y array values into it. And then closes the file.
Reading from and Writing into the File
The read and write statements respectively are used for reading from and writing into a file respectively.
In most programming languages, a pointer variable stores the memory address of an object. However, in Fortran, a pointer is a data object that has more functionalities than just storing the memory address. It contains more information about a particular object, like type, rank, extents, and memory address.
A pointer is associated with a target by allocation or pointer assignment.
Declaring a Pointer Variable
A pointer variable is declared with the pointer attribute.
The following examples shows declaration of pointer variables −
integer, pointer :: p1 ! pointer to integer
real, pointer, dimension (:) :: pra ! pointer to 1-dim real array
real, pointer, dimension (:,:) :: pra2 ! pointer to 2-dim real array
A pointer can point to −
An area of dynamically allocated memory.
A data object of the same type as the pointer, with the target attribute.
Allocating Space for a Pointer
The allocate statement allows you to allocate space for a pointer object. For example −
program pointerExample
implicit none
integer, pointer :: p1
allocate(p1)
p1 = 1
Print *, p1
p1 = p1 + 4
Print *, p1
end program pointerExample
When the above code is compiled and executed, it produces the following result −
1
5
You should empty the allocated storage space by the deallocate statement when it is no longer required and avoid accumulation of unused and unusable memory space.
Targets and Association
A target is another normal variable, with space set aside for it. A target variable must be declared with the target attribute.
You associate a pointer variable with a target variable using the association operator (=>).
Let us rewrite the previous example, to demonstrate the concept −
When the above code is compiled and executed, it produces the following result −
1
1
5
5
8
8
A pointer can be −
Undefined
Associated
Disassociated
In the above program, we have associated the pointer p1, with the target t1, using the => operator. The function associated, tests a pointer’s association status.
The nullify statement disassociates a pointer from a target.
Nullify does not empty the targets as there could be more than one pointer pointing to the same target. However, emptying the pointer implies nullification also.
program pointerExample
implicit none
integer, pointer :: a, b
integer, target :: t
integer :: n
t = 1
a => t
t = 2
b => t
n = a + b
Print *, a, b, t, n
end program pointerExample
When the above code is compiled and executed, it produces the following result −
Fortran allows you to define derived data types. A derived data type is also called a structure, and it can consist of data objects of different types.
Derived data types are used to represent a record. E.g. you want to keep track of your books in a library, you might want to track the following attributes about each book −
Title
Author
Subject
Book ID
Defining a Derived data type
To define a derived data type, the type and end type statements are used. . The type statement defines a new data type, with more than one member for your program. The format of the type statement is this −
type type_name
declarations
end type
Here is the way you would declare the Book structure −
type Books
character(len = 50) :: title
character(len = 50) :: author
character(len = 150) :: subject
integer :: book_id
end type Books
Accessing Structure Members
An object of a derived data type is called a structure.
A structure of type Books can be created in a type declaration statement like −
type(Books) :: book1
The components of the structure can be accessed using the component selector character (%) −