Pointers

Variable Declarations

      Declarations served dual purpose

   Specification of range of values and operations

   Specification of Storage requirement

 

      All programs required FIXED amount of memory

   number of variables fixed by the declaration

   decided by their types

 

      One exception:  Allocatable array

   Size of the array depends upon input

Static and Dynamic Allocation

      Compiler uses the declaration to allocate memory for a program

      Static allocation (or fixed  memory requirements) leads you to be conservative

      Wastage of space and poor performance for some inputs

      Analogy:  Two-way traffic in City roads

      Better management: allocate on demand

    Initially allocate minimal

    Allocate more when needed

    Deallocate when not needed

    Dynamic Memory management

Dynamic Memory allocation

      Memory allocation not fixed

      nor done at compile-time

      It is done at run-time

      at run-time no declarations - only executable instructions

      need special instructions for allocation - executable declarations so to say

      Allocate and Deallocate constructs for dynamic arrays

      we need more general mechanism for arbitrary organization of data

Pointers

      One problem with dynamic allocation:

      How do we access the newly allocated memory locations

      How did we access the statically allocated memory?

      Access the new locations by their addresses

      This is against the principle of high level languages:

   abstract memory locations and machine details

   disallow direct control over resources unsafe

      is there any other way?

      pointer variables is a compromise

      Pointer variable contains addresses rather than data values

      Addresses point to the newly allocated memory locations and hence called pointers

Pointer variables

      They store addresses that identify locations where actual data values reside

      Pointer variables declared statically so compiler can allocate memory

      Static declaration of pointer variables! That is funny

    we do not know a priori our memory requirement and hence our quest for dynamic memory locations

      Static declarations can allocate only a fixed number of pointers

      How do we create and access unbounded number of locations

      Answer: Dynamic creation of pointers themselves (more on this later)

Pointer variable Declarations

      Declarations specify types - set of data values and operations

      What types pointers are or should be?

      Pointer variables store addresses

      Addresses are numerical values - non negative integers

      Are they non negative integers? No, quite a different kind

      Pointers always contain same type of values whatever they point to

   Can point to integers, reals, characters, arrays or structures

      Are all pointers of the same type

Pointers are of different types

      Only way of accessing dynamic objects is through pointers

      What is pointed to is distinguished - real, integer, character, array etc.

      Essential to distinguish the pointers for the same reason

      So Pointers are of different types:

   integer pointer, real pointer, array pointer, etc

      Pointer types are decided by the types of those pointed to

      Declarations specify these

Pointer Declarations

      Examples:

            integer, pointer:: p1, p2

            real, pointer:: r1, r2

 

            integer, dimension(:), pointer:: array_ptr

            real, dimension(:,:), pointer:: matrix_ptr

      These declarations allocate memory for the pointer variables

      Pointer variables have addresses like normal addresses

      But they store addresses - the addresses will be assigned dynamically (during execution)

      Addresses assigned should correspond to locations where data values with the specified type is stored

      Special statements are provided for this purpose

Target variables

      Simplest pointer assignment:

   store the address of a location allocated for a variable

      Example:

          p1 => x

          r1 => z

          matrix_ptr => m

    where

      p1,r1, matrix_ptr as before

      x,z,m are integer, real and matrix variables

      The types should match

      rhs variables resolved to addresses!

   contrast with conventional assignment

Pointer assignment

 

 

Target declarations

      For a variable to act as target explicit declaration required:

 

          integer, target :: x

          real, target :: z

          integer, dimension(10,10), target :: matrix_ptr

Targets can be pointers

      Suppose p1 and p2 are of pointers of the same type

 

      Further suppose p2 points to a location of appropriate type

 

      Then

            p1 => p2

 

      makes p1 point to whatever p2 points to

 

Before Assignment

 

 

 

After assignment

 

 

 

Dereferencing of pointers

      Two meanings for pointers in

          p1 => p2

      p2 has an address and contains another address

      What is assigned to p1 is the content of p2

      p2 on the rhs refers to the contents of p2 rather than p2 itself

      This is called Dereferencing

      Contrast this when target is ordinary variable

          p1 => x

   what is assigned here is not the content of x but the address of x

Another example

      Consider

  

write *, p1, p2

 

      What is printed?

      The address associated with p1,p2?

      No, the values stored at those addresses

      The pointers are dereferenced to get the values

Pointers in Normal Assignment

      Pointers can appear in normal assignments:

         p1 = p2

         p1 = p2 + p3

 

      Suppose, p1, p2 and p3 points to targets x, y and z

      The above is equivalent to

          x = y

          x = y + z

 

      Note that p1 is also dereferenced here

Rules for dereferencing

=>

      The lhs should be evaluated to an address (or pointer)

      The rhs should also evaluate to an address

=

      The lhs should evaluate to an address

      The rhs should evaluate to a value

print *, x

   x should be a value

      So the rule is:

             Dereference the pointer as much required to         evaluate to appropriate value

Use of Pointers

       Suppose you wish to exchange two arrays arr1, arr2 of Dimension(100,100)

       Solution 1:

            temp = arr1

            arr1 = arr2

            arr2 = temp

       involves exchange of 10,000 values!

       Solution 2:

            Real, Dimension(:,:), pointer:: p1,p2,temp

            p1 => arr1

            p2 => arr2

            temp => p1

            p1 => p2

            p2 => temp

       Exchange of just two pointers

Dynamic Allocation of Memory

      So far, pointers point to already existing variables

      The amount of used memory is still static

      For dynamic memory requirement, additional mechanism needed

      Allocate and Deallocate instructions

      Allocate creates required memory and decllocate destroys memory

Allocate Command

      Simplest allocate statement

                Allocate(p, stat = s)

      This allocates appropriate memory space,

      address pointed to by the pointer p

      s returns an integer value which indicates whether allocation successful or not

          s = 0 means success,

                    failure otherwise

      Stat = is optional but should always be used

      If allocation fails and if no stat = clause, then the program will abort

Some examples

             integer, pointer:: p1

          integer, dimension(:):: p2

          ...

          allocate(p1, Stat=p1_stat)

          allocate(p2(1:10), Stat = p2_stat)

          '''"

 

          p1 = x + y

          p2(2) = p2(1) + p1

 

      Note the dimension specification in p2 declaration

Deallocate Command

      Memory created using Allocate command can be destroyed when not needed

   Deallocate(p, Stat = p_stat)

      Deallocates the memory, if p_stat = 0

      What does p point to after this command?

      It points to null value

      Pointer assignment or allocation associates the pointer with some address

      Deallocation breaks this association

      Referring to pointer that is disassociated is an error

   The program will abort

Checking Association

      To avoid aborting, association status of pointer should be checkable

      Intrinsic function Associated  used for this purpose

associated(p)

      returns the value .TRUE. iff p is associated with a target

      A more general form is

                associated(p, tvar)

      returns .TRUE iff p is associated with the target tvar

      Association with a pointer can be removed using

                nullify(p)

      which disassociates p with any target.

Pointers - serious safety hazard

      Conventional variables have many nice features:

   unique association of memory with variables

   distinct variables - distinct locations

   one without the other not possible

      Pointers provides flexibility and more control

      But at the cost of safety

      It is a low-level feature

      No unique association of pointers to targets

      More than one pointer to the same target or location

      Pointer without location (dangling pointers)!

      Location without any pointers too (memory leak or garbage)!

Multiple Associations

            p1 => x

            p2 => p1

            p3 => p2

            p4 => x

      All point to the same location

 

 

Dangling Pointers

      What is the problem with multiple associations?

      value pointed to by p1 can be changed independently

            p1 = 10

            p2 = 17

            p1 = p1 + 1

     p1 points to a location which contains 18 and not 11

      More serious problem:

            p1 = 10

             deallocate(p2)

            p1 = p1 + 2

      p1 is pointing to a location which is deallocated

      p1 is a dangling pointer

      no control over what value the deallocated memory will contain

Memory Leak

      Only way of accessing dynamically allocated memory is via pointers

      Suppose there is only one pointer p pointing a location

      nullify(p) disassociates p

      The memory is no longer accessible

      Memory has leaked out - memory has become garbage

      Deallocation done before memory leaks out

      Wastage of space

      Separate Garbage collection phase