[comp.sys.sgi] Passing an array of strings to FORTRAN

burow@cernvax.cern.ch (burkhard burow) (01/29/91)

I'm calling FORTRAN routines from C routines. The FORTRAN manual tells me how
to pass, among other kinds of arguments, strings and arrays of numbers. But it
doesn't tell me:

QQQQQQQ:        How do I pass an array of strings? 

There are many best guesses to try out, but I was hoping a netter could give me
the answer.

thanks              INTERNET:  burow%13313.hepnet@csa3.lbl.gov
burkhard

merritt@iris613.gsfc.nasa.gov (John H Merritt) (01/29/91)

In article <3966@cernvax.cern.ch> burow@cernvax.cern.ch (burkhard burow) writes:
>I'm calling FORTRAN routines from C routines. The FORTRAN manual tells me how
Actually, the manual is not 100% clear on this.  It is not clear on
where the extra arguments (string lengths) are placed in the argument
list when Fortran compiles.  The constants string_lengths are placed LAST
in the argument list and in the order that the strings appear; one for
each string.

>to pass, among other kinds of arguments, strings and arrays of numbers. But it
>doesn't tell me:
>
>QQQQQQQ:        How do I pass an array of strings? 
This is a tricky problem.
For each array that you pass you must specify the string length as a 
constant and place it at the end of the argument list.  If you have
more than one string array passed, then list the constant lengths sequentially,
and in the order that the arrays appear, at the end of the parameter list.

You have to be conscience about setting up the C string arrays.
For one thing they must not contain any unexpected NULL characters.
Remember the storage is sequential.  Here is an example of a FAILING program,
followed by one that performs correctly.

- cut Fortran subroutine (not changed for both FAILING and Working C mains) -
      subroutine t(name, n2, a, b, c)
      character *(*) name(4), n2(3)

      print*,'len(name(1))  =',len(name(1))
      print*,'len(name(2))  =',len(name(2))
      print*,'len(name(3))  =',len(name(3))
      print*,'len(name(4))  =',len(name(4))
      print*,'len(n2(1))    =',len(n2(1))
      print*,'len(n2(2))    =',len(n2(2))
      print*,'len(n2(3))    =',len(n2(3))
      print*,'a',a
      print*,'b',b
      print*,'c',c
      print*,'name(1) =',name(1)
      print*,'name(2) =',name(2)
      print*,'name(3) =',name(3)
      print*,'name(4) =',name(4)
      print*,'n2(1) =',n2(1)
      print*,'n2(2) =',n2(2)
      print*,'n2(3) =',n2(3)
      return
      end
- end cut -

---- cut C main for the FAILING program ----
main()
{
  static char str[4][2] = {"1", "2", "3", "4"};
  static char s2[3][6]  = {"55555", "66666","77777"};

  float a = 10.0;
  float b = 20.0;
  float c = 30.0;

  t_(str, s2, &a, &b, &c, strlen(str[0]),strlen(s2[0]));

}
---- end cut C main for the FAILING program ----

When running this example you will see that the lengths for each
string array are passed correctly, however on output the 
printed characters show the NULL's that are stored.  Note: that
the C character declarations have space for the terminating NULL characters.

So the solution is to load the C arrays with exactly the characters you
want and exactly specify the strings lengths yourself.  I.e., you cannot
use strlen because it relies on the NULL character to determine string
lengths.

---- cut C main for the WORKING program ----
main()
{
  char str[4][1];
  char s2[3][5];
  float a = 10.0;
  float b = 20.0;
  float c = 30.0;

  strncpy(str[0], "1", 1);
  strncpy(str[1], "2", 1);
  strncpy(str[2], "3", 1);
  strncpy(str[3], "4", 1);
  strncpy(s2[0], "55555", 5);
  strncpy(s2[1], "66666", 5);
  strncpy(s2[2], "77777", 5);

  t_(str, s2, &a, &b, &c, 1, 5);

}
---- end cut C main for the WORKING program ----

Oh, now we are happy.

              John H. Merritt --> merritt@iris613.gsfc.nasa.gov
              Applied Research Corporation at NASA/GSFC
              "Yesterday I knew nothing, today I know that."