This next example adds 7.0 to all the values in the main data array of the input NDF. Although not the most useful of applications in itself, it does illustrate the method usually used in ADAM programs to manipulate data arrays and introduces the concept of dynamic memory mapping.
And the interface file:
Dynamic memory mapping.
In order to get access to a data array, a Fortran program might declare an array of some fixed size, and read the data values into it. The problems with this approach are that such a program will contain an array larger than necessary for most purposes, and cannot deal with an array larger than that explicitly declared.
The solution is to exploit the method that most compilers use to pass values between subroutines. When a value is passed from one program unit to another via an argument list, usually9 what is transferred is not the value itself, but simply the address of the storage location where the value is held. Thus a subroutine to which an array is passed does not have its own copy of that array, but just knows where to find it.
In the example program, ADD7, you will notice that the main subroutine does not declare an array at all. However it does have the INTEGER PTR1. The ‘map’ call below reads the data from the NDF into the computer’s memory, and returns the pointer PTR1 whose value is the actual memory address of the first byte of the allocated memory. Also returned is NELM, the number of elements in the data array.
This address (PTR1) cannot be used to access the data array in the subroutine ADD7. But it can be used in the call to the subroutine ADDIT. Merely inserting PTR1 into the argument list of the call to ADDIT will not produce the desired result. This is because the subroutine will receive not the actual value of PTR1, but the address of PTR1 itself, and thus will simply have access to the integer variable PTR1 (as you would expect).
However, VAX Fortran supports a special extension called %VAL, which forces the actual value of a variable to be passed to the subroutine.10 Thus in the call below, passing the argument %VAL(PTR1) is equivalent to actually passing the data array whose address is stored in PTR1.
An array of the correct size can then be declared in the subroutine ADDIT thus:
ADDIT now operates directly on the array in memory just as if it had received it in the normal way.
In this example the array is mapped for ’UPDATE’ so when it is ‘unmapped’, the modified array is automatically written back into the NDF. (There is no explicit ‘unmap’ call in the example shown here, because the NDF_END will automatically annul the NDF1 identifier, and this unmaps any mapped arrays associated with that identifier.)
Several points should be noted:
If you are not convinced you can compile and link the program and try it on the 1-d SPECTRUM.SDF and 2-d IMAGE.SDF. (All the necessary files can be copied from ADAM_EXAMPLES.) Doing a TRACE on these files before and after program execution should confirm that the addition has been carried out.
9There is nothing in the Fortran standard to enforce this passing by address, so the method is not guaranteed to work on any computer.
10This passing by value is used when interfacing Fortran with C routines; the latter might need to receive not the address of a variable, but its actual value. The %VAL extension is supported by compilers on both SUN and Convex machines.