Fortran

Derived types (structures) and Pointers

notes by Lin Jensen, Bishop's University

Topics in this file:

Derived types (structures)

A derived type, or structure, is a collection of named components (variables, arrays, other types), similar to a "record" in Pascal or a "structure" in C.

A structure can be referred to as a whole, and its components can also be referenced, using the % sign (rather than the dot . of other languages). A structure may be read or written, and the effect is the same as if its components were listed in order in the data list.

For example, a city can be described by its name, population, latitude, longitude and elevation:

    TYPE :: City
        character(20) :: Name
        integer       :: Population
        real          :: Latitude, Longitude    !! degrees north & west
        integer       :: Elevation              !! in meters
    END TYPE City
Now variables of the new type may be declared, and assigned values using a structure constructor:
    TYPE(City) :: Lennox, &
                  Hatley = City("Hatley Village",674, 45.2, 72.9, 300)
Individual components of a structure can be referenced using a %
    Lennox%Name = "Lennoxville"
    print *, Hatley%Population, " inhabitants"

Pointers

A pointer is a variable name which can be used as an "alias" for another variable. The other variable can either be a named variable, or unnamed storage space allocated by an ALLOCATE statement. This can be dangerous, therefore the other variable must have the TARGET attribute specified, this gives permission to have a pointer variable aliased to the target.

Pointer variables are initially disassociated, and may become associated with values through pointer assignment => or an ALLOCATE statement. Pointers can be reassigned, breaking any previous association, or disassociated by NULLIFY. For example:

    REAL, TARGET :: Pi = 3.14159
    REAL, POINTER:: Cake, Ice_Cream
 
    Cake => Pi            !! Cake is associated with target Pi
    ALLOCATE (Ice_Cream)  !! Associate with unnamed storage
    Ice_Cream = Pi        !! Copy value of Pi to the unnamed storage
    Cake = -98.6          !! Watch out! Pi changes also
    PRINT *, Pi, Ice_Cream !!  prints  -98.6   3.14159 

A pointer's association status may also become "undefined." This is also known as the dangling pointer problem.

    Cake => Ice_Cream     !! Cake now associated with unnamed storage
    DEALLOCATE (Cake)     !! Cake now disassociated, and storage released
                          !! Ice_Cream is left UNDEFINED      

Linked Lists

For a complete example, I have written a
module using linked lists to implement an abstract data type LIST.

Structures and pointers can be combined nicely to form dynamic, linked data structures such as linked lists and binary trees. One needs a structure including some data, and a pointer to another such structure, the next set of data in a list. In this list of animal chasing order, head is an extra pointer to the first item in the list, each node has a pointer Next. The Next pointer of the last node in a list is generally disassociated, here shown as a red box.

Dog -- Cat -- Mouse

The structure is defined as follows:

    TYPE :: Node
        Character(6)        :: Animal
        TYPE(Node), POINTER :: Next
    END TYPE Node
 
    TYPE(Node), POINTER  :: Head, TemP    !! Initially empty list
and the list can be created by ALLOCATE space, and filling it in, assigning links with pointer assignment, from right to left:
    ALLOCATE (Head)
    Head%Animal = "Mouse"
    NULLIFY (Head%Next)        !! no next item
 
    ALLOCATE (TemP)
    TemP%Animal = "Cat"
    TemP%Next   => Head        !! Link Cat to Mouse
    Head        => TemP        !! Make Cat the new head
 
    ALLOCATE (TemP)            !! Can now reuse TemP
    TemP%Animal = "Dog"
    TemP%Next   => Head
    Head        => TemP        !! Dog is now at Head
    NULLIFY (TemP)                !! No longer need service of TemP
We can traverse the list, printing the entries, as follows:
    TemP => Head
    DO WHILE (ASSOCIATED(TemP))
        PRINT *, TemP%Animal
        TemP => TemP%Next
    END DO
It would also be possible, and perhaps more intuitive, to build the list from left to right:
  print *,"Enter animals, one per line, blank line when done"
    ALLOCATE (Head)
    TemP => Head
    READ '(A)', TemP%Animal
    DO WHILE (TemP%Animal /= ' ')        !!until blank line entered    
        ALLOCATE (TemP%Next)             !!create new node and link to it  
        TemP => TemP%Next                !! work with new node
        READ '(A)', TemP%Animal
    END DO
    NULLIFY (Temp%Next)                  !! Final node points nowhere
Now the animals are linked in the order they were entered. There is also a final node with blank for animal, and Next disassociated. This can be used as a sentinal value. It is awkward to remove it.

In the preceeding example, the only data in each node was a single word. It could just as well be any type or types of data, including another structure or array(s).


Last updated 4 April 1996.
Fortran notes by Lin Jensen

To top of this document
Back to Fortran page
Back to Lin Jensen's home page