9 More on Arrays

 9.1 CHARACTER and LOGICAL Arrays
 9.2 Arrays of pointer to char
 9.3 POINTER Arrays

For most data types arrays are handled simply, using pointers as already demonstrated. However, for arrays of some types the data in the arrays must be converted back and forth between C and FORTRAN representations. Macros and functions are provided to facilitate the conversions.

Very often, the actual size of the FORTRAN array required will not be known until runtime so space for it must be allocated dynamically in a similar way to dynamic character strings.

Macros DECLARE_type_ARRAY_DYN and F77_CREATE_type_ARRAY are defined to do this. They are designed for 1-dimensional arrays, having just the name and the number of elements as parameters, but for Unix systems, at least, will work for multi-dimensional arrays.

For most types on all current systems, the CREATE_ARRAY macros will not actually allocate space as no conversion of data is necessary, but they are provided for contingency and completeness.

9.1 CHARACTER and LOGICAL Arrays

There are two versions of the macros for creating dynamic CHARACTER and LOGICAL arrays: F77_CREATE_CHARACTER_ARRAY will create a 1-dimensional array with the given number of elements, and F77_CREATE_CHARACTER_ARRAY_M will create an array whose size is defined by an integer specifying the number of dimensions and an array of integers specifying each dimension. Similarly F77_CREATE_LOGICAL_ARRAY and F77_CREATE_LOGICAL_ARRAY_M

Consider the following example of a C program which calls a FORTRAN subroutine which returns a CHARACTER array produced by setting to blank every non-blank element of a given array for which the corresponding element of a given LOGICAL array is TRUE. A LOGICAL output array is produced with TRUE in the element corresponding with each element of the CHARACTER array which has been reset, and FALSE elsewhere.

Example 8 – Import and export of arrays..
  #include <stdio.h>
  #include "f77.h"
  F77_SUBROUTINE(str_reset)(CHARACTER_ARRAY(in), LOGICAL_ARRAY(lin),
                            INTEGER(dim1), INTEGER(dim2),
                            CHARACTER_ARRAY(out), LOGICAL_ARRAY(lout)
                            TRAIL(in) TRAIL(out) );
  
  void main(){
  char inarr[3][2][4]={{"Yes","No "},{"   ","   "},{"No ","Yes"}};
  int inarr_length=4;
  char outarr[3][2][4];
  int outarr_length=4;
  int lin[3][2]={{1,0},{1,1},{0,1}};
  int lout[3][2];
  DECLARE_CHARACTER_ARRAY(fin,3,2][4);
  DECLARE_CHARACTER_ARRAY_DYN(fout);
  DECLARE_LOGICAL_ARRAY(flin,3][2);
  DECLARE_LOGICAL_ARRAY_DYN(flout);
  DECLARE_INTEGER(dim1);
  DECLARE_INTEGER(dim2);
  int ndims=2;
  int dims[2]={3,2};
  int i,j;
  
     F77_CREATE_CHARACTER_ARRAY_M(fout,3,ndims,dims);
     F77_CREATE_LOGICAL_ARRAY_M(flout,ndims,dims);
  
     (void) cnfExprta(
        (char *)inarr, inarr_length, (char *)fin, fin_length, ndims, dims );
     (void) cnfExpla( (int *)lin, (F77_LOGICAL_TYPE *)flin, ndims, dims );
  
     dim1 = dims[0];
     dim2 = dims[1];
  
     F77_CALL(str_reset)( CHARACTER_ARRAY_ARG(fin), LOGICAL_ARRAY_ARG(flin),
                       INTEGER_ARG(&dim1), INTEGER_ARG(&dim2),
                       CHARACTER_ARRAY_ARG(fout), LOGICAL_ARRAY_ARG(flout)
                       TRAIL_ARG(fin) TRAIL_ARG(fout) );
  
     (void) cnfImprta
             ( fout, fout_length, outarr[0][0], outarr_length, ndims, dims );
     (void) cnfImpla( (F77_LOGICAL_TYPE *)flout, (int *)lout, ndims, dims );
  
     F77_FREE_CHARACTER(fout);
     F77_FREE_LOGICAL(flout);
  
     printf("i j in  lin out lout\n");
     for (j=0;j<3;j++){
        for (i=0;i<2;i++){
           printf("%d %d %c  %s  %c  %s\n",
              i, j, lin[j][i]?’T’:’F’, inarr[j][i],
                    lout[j][i]?’T’:’F’, outarr[j][i] );
        }
     }
  }

        SUBROUTINE STR_RESET( ARRAY, LIN, DIM1, DIM2, OUT, LOUT )
  *  Purpose:
  *     Reset elements of an array
  
  *  Arguments:
  *     ARRAY(2,3)=CHARACTER*(*) (Given)
  *        The array to be altered
  *     LIN(2,3)=LOGICAL (Given)
  *        The given LOGICAL array
  *     DIM1=INTEGER (Given)
  *        The first dimension of the arrays
  *     DIM2=INTEGER (Given)
  *        The second dimension of the arrays
  *     OUT(2,3)=CHARACTER*(*) (Returned)
  *     LOUT(2,3)=LOGICAL (Returned)
  
        IMPLICIT NONE
        INTEGER I, J
        INTEGER DIM1, DIM2
        CHARACTER*(*) ARRAY(2,3)
        CHARACTER*(*) OUT(2,3)
        LOGICAL LIN(2,3)
        LOGICAL LOUT(2,3)
  
        DO 20, J = 1, 3
           DO 10, I = 1, 2
              IF( LIN(I,J) .AND. (ARRAY(I,J) .NE. ’ ’) )THEN
                 OUT(I,J) = ’ ’
                 LOUT(I,J) = .TRUE.
              ELSE
                 OUT(I,J) = ARRAY(I,J)
                 LOUT(I,J) = .FALSE.
              END IF
  10       ENDDO
  20    ENDDO
  
        END

As an example of how to write a C function to be called from FORTRAN with array arguments, the above subroutine could be re-written in C as follows:

  #include "f77.h"
  
  F77_SUBROUTINE(str_reset)(CHARACTER_ARRAY(in_f), LOGICAL_ARRAY(lin_f),
                            INTEGER(dim1), INTEGER(dim2),
                            CHARACTER_ARRAY(out_f), LOGICAL_ARRAY(lout_f)
                            TRAIL(in_f) TRAIL(out_f) )
  {
  GENPTR_CHARACTER_ARRAY(in_f)
  GENPTR_LOGICAL_ARRAY(lin_f)
  GENPTR_INTEGER(dim1)
  GENPTR_INTEGER(dim2)
  GENPTR_CHARACTER_ARRAY(out_f)
  GENPTR_LOGICAL_ARRAY(lout_f)
  
  int i, j, nels, cpt;
  char *in_c, *out_c;
  int *lin_c, *lout_c;
  int ndims=2;
  int dims[2];
  
     dims[0] = *dim1;
     dims[1] = *dim2;
     nels = *dim1 * *dim2;
  
     in_c = cnfCreat( nels*(in_f_length+1) );
     out_c = cnfCreat( nels*(out_f_length+1) );
     lin_c = (int *)malloc( nels*sizeof(int) );
     lout_c = (int *)malloc( nels*sizeof(int) );
     cnfImprta( in_f, in_f_length, in_c, in_f_length+1, ndims, dims );
     cnfImpla( lin_f, lin_c, ndims, dims );
  
     cpt = 0;
     for(i=0;i<nels;i++){
        if( *(lin_c+i) && strlen( in_c+cpt ) ) {
            strcpy(out_c+cpt,"");
            *(lout_c+i) = 1;
        } else {
            strcpy( out_c+cpt, in_c+cpt );
            *(lout_c+i) = 0;
        }
        cpt += in_f_length+1;
     }
  
     cnfExprta( out_c, out_f_length+1, out_f, out_f_length, ndims, dims );
     cnfExpla( lout_c, lout_f, ndims, dims );
  
     cnfFree( in_c );
     cnfFree( out_c );
     free( lin_c );
     free( lout_c );
  }

9.2 Arrays of pointer to char

In C, arrays of character strings are often held as arrays of pointer to char. This allows strings of varying length and not necessarily in contiguous memory. CNF functions cnfImprtap and cnfExprtap can be used to import/export arrays of pointer to char from/to FORTRAN CHARACTER arrays. The following example shows how to do this. The FORTRAN subroutine, PRARR, prints the given CHARACTER array and returns it set to blank strings. The C program prints the strings before and after the call to PRARR.

Example 9 – IMPORT/EXPORT with arrays of pointers to char.
  rlsaxp_101% more temp.c
  #include "f77.h"
  F77_SUBROUTINE(prarr)(CHARACTER_ARRAY(arr) TRAIL(arr));
  main() {
  DECLARE_CHARACTER_ARRAY(arr,12,3);
  char *ptr[3]={"ajc","hello there","TEXT"};
  int dims[1]=3;
  int i;
  
  for (i=0;i<3;i++) printf("%d:%s:\n",i,ptr[i]);
  cnfExprtap(ptr,arr[0],12,1,dims);
  F77_CALL(prarr)(CHARACTER_ARRAY_ARG(arr) TRAIL_ARG(arr));
  cnfImprtap(arr[0],12,ptr,1,1,dims);
  for(i=0;i<3;i++) printf("%d:%s:\n",i,ptr[i]);
  }

        SUBROUTINE PRARR( ARR )
        CHARACTER*(*) ARR(3)
        INTEGER I
  
        DO 10
           PRINT *, ’:’, ARR(I), ’:’
           ARR( I ) = ’ ’
  10    CONTINUE
        END

9.3 POINTER Arrays

An array of pointers would need to be converted back and forth between the C and FORTRAN representations to cope with the possibility that the length of a C pointer is not the same as the length of a FORTRAN INTEGER. This can be done by declaring a suitably-sized FORTRAN array and converting each element using either cnfCptr or cnfFptr, according to the direction of conversion.

For example, to call a FORTRAN subroutine which returns an array of three pointers to real, the C code would need to be something like:

  F77_REAL_TYPE * pntr[3]
  DECLARE_POINTER_ARRAY(fpntr,3)
  
  F77_CALL(getptr)(POINTER_ARRAY_ARG(fpntr))
  /* Import the pointers to C */
  for (i=0;i<3;i++) pntr[i]=(F77_REAL_TYPE *)cnfCptr(fpntr[i]);

See also The IMPORT and EXPORT macros (Section 10).