[net.lang.f77] arrays, anyone?

dave@ur-helheim.UUCP (Dave Carlson) (08/30/85)

Given a dimensioned fortran array A(50,300), I will set element A(10,100)=666,
just so a unique value is present.  Now I pass the array to a c program via
the argument list.  Given the column/row major differences, I can address the
fortran element A(10,100) as *(apntr+9*300+99) and get the correct answer.  
The hassle with this is that the dimensionality of the array must be known to
the c program, ie. 300 must be known.  Now, in C 2-d arrays are simply an array
of pointers to a linear array.  My question is can I access the fortran array
above as a double indirection + offset, as I would a C array?  Is there any way
of accessing the array that does not need to know the dimensions to get the 
offset?  [Suggestions like 'do it in fortran' are not needed--thanks!!]

thanks in advance.

"The Faster I Go the Behinder I Get"
--Lewis Carroll

Dave Carlson

{allegra,seismo,decvax}!rochester!ur-valhalla!dave
-- 
"The Faster I Go the Behinder I Get"
--Lewis Carroll

Dave Carlson

{allegra,seismo,decvax}!rochester!ur-valhalla!dave

throopw@rtp47.UUCP (Wayne Throop) (09/02/85)

> Given a dimensioned fortran array A(50,300), I will set element
> A(10,100)=666, just so a unique value is present.  Now I pass the array
> to a c program via the argument list.  Given the column/row major
> differences, I can address the fortran element A(10,100) as
> *(apntr+9*300+99) and get the correct answer.  The hassle with this is
> that the dimensionality of the array must be known to the c program, ie.
> 300 must be known.

So far so good.

> Now, in C 2-d arrays are simply an array of pointers to a linear array.

Slight misconception here.  In C, multi-dimensional arrays are *not*
arrays of pointers to linear arrays.  See the declarations below:

    int a[2][3];                /* multi-dimensional array */
    int (*a[2]);                /* array of pointers to arrays of
                                   indefinite size */
    int (*a)[3];                /* pointer to array of indefinite size
                                   of arrays of 3 ints */

FORTRAN can express only the first notion (since FORTRAN lacks pointers).

The diference between C multi-dimensional arrays and FORTRAN
multi-dimensional arrays is that C arrays are stored in what is often
called "odometer order", while FORTRAN arrays are stored in
"anti-odometer order".  That is, the elements of the above declared
multi-dimensional array are stored in this order:

        a[0][0], a[0][1], a[1][2], a[1][0], a[1][1], a[1][2]

while the fortran array declared

        INTEGER A(2,3)

is stored in this order:

        A(1,1), A(2,1), A(1,2), A(2,2), A(1,3), A(2,3)

By the way, *(a+9*300+99) or a[9*300+99] to get at A(10,100) should
*NOT* have worked, since it assumes FORTRAN stores arrays in "odometer"
order.  (It also assumes that FORTRAN passes an array by placing the
address of the array on the stack in a C-compatible form, but his is
often the case, and is thus a "safe" assumption.) Anyway, what is needed
is a[9+50*99].

> My question is can I access the fortran array above as a double
> indirection + offset, as I would a C array?  Is there any way of
> accessing the array that does not need to know the dimensions to get the
> offset?  [Suggestions like 'do it in fortran' are not needed--thanks!!]

As indicated above, the C declaration "int a[3][2];" is "equivalent to"
the fortran "INTEGER A(2,3)", (where all appropriate indices are
swapped on references).  Thus, you should be able to do something like
this:

        FORTRAN main program:

                    INTEGER A(2,3)
                    CALL INIT(A)
                    DO 100 I=1,2
                        DO 90 J=1,3
                            PRINT *, A(I,J)
             90         CONTINUE
            100     CONTINUE
                    STOP
                    END

        C subroutine to initialize the array:

            void INIT(a) int a[3][2]; {
                int i,j,k=0;
                for(i=0;i<2;i+=1){
                    for(j=0;j<3;j+=1){
                        a[j][i] = ++k;
                    }
                }
            }

        And get the output I did, namely:

            1
            2
            3
            4
            5
            6

Now then, as to *implicitly* passing the "shape" of the array from
FORTRAN to C, there is no real way to do that.  The closest (even
somewhat portable) way I can see to do that is like so:

        INTEGER A(2,3)
        CALL CSUBR(A,2)
        ...

        void CSUBR(a,n) int a[], *n; {
            ... a[i+(*n)*j] ...; /* access FORTRAN array element A(i+1,j+1) */
        }

Which corresponds closely to the usual FORTRAN idiom of

        INTEGER A(2,3)
        CALL FSUBR(A,2,3)
        ...

        SUBROUTINE FSUBR( A, N, M )
        INTEGER A(N,M)
            ... A(I,J) ...      ! access FORTRAN array element A(I,J)

So...   why don't you do it in FORTRAN?     :-)

> Dave Carlson
> {allegra,seismo,decvax}!rochester!ur-valhalla!dave
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!rtp47!throopw

guy@sun.uucp (Guy Harris) (09/03/85)

(net.lang.c added because this provides a small tutorial in one of the
least-understood parts of C - arrays)

> Given a dimensioned fortran array A(50,300) ... Now I pass the array to a
> c program via the argument list.  Given the column/row major differences,
> I can address the fortran element A(10,100) as *(apntr+9*300+99) and get
> the correct answer.

1) This assumes you declared "apntr" as an "float *" - which isn't the
correct thing to do.  See below.

2) Besides, I think you actually mean *(apntr + 99*50 + 9).  In FORTRAN, the
rightmost index selects the largest objects, and the leftmost index selects
the smallest objects; i.e., stepping the leftmost index by 1 steps from one
array member to the next adjacent one in the address space.

> The hassle with this is that the dimensionality of the array must be known
> to the c program, ie. 300 must be known.

(Well, actually, you mean the 50 must be known - see above.)  What's so
surprising about that?  The same would be the case if you passed A to a
FORTRAN subroutine or function.  You could give the argument to the FORTRAN
program variable dimensions, and pass the 50 and 300 as arguments, or you
could explicitly declare it as an array with 50 rows of 300 columns.  In
*either* case, "the dimensionality of the array must be known to the FORTRAN
program, i.e., 50 must be known."  (The 300 need not be known unless you're
doing bounds checking, since it doesn't affect any of the array strides.)

> Now, in C 2-d arrays are simply an array of pointers to a linear array.

No, they aren't.  In C, 2-dimensional arrays are simply arrays of arrays.
There are *NO* pointers involved.  They are laid out in memory much as
FORTRAN arrays are, only in a different order.

Arrays in C seem to cause an inordinate amount of confusion.  Amazingly
enough, the type "pointer to array of 'float'" and "pointer to 'float'" are
*NOT* the same type.  Declaring "x" as a "pointer to array of 'float'" is done
with

	float (*x)[];

while declaring "x" as a "pointer to 'float'" is done with

	float *x;

(Think about it - the syntax of declarations of data types in C parallels
the syntax used to refer to the base object that an object of that data type
refers to.  If you have a pointer to an array, first you dereference it to
get the array, then you subscript the array.  Hence, (*x)[12] refers to the
12th element of that array.)

The FORTRAN program is passing a pointer to an array of REALs, with 50 rows
and 300 columns.  The C equivalent of this is a pointer to an array of 300
arrays of 50 "float"s.  An array of 50 "float"s:

	float a[50];

An array of 300 arrays of 50 "float"s:

	float a[300][50];

A pointer to such an array:

	float (*a)[300][50];

Now, to reference A(10,100):

	(*a)[99][9];

(Remember, C and FORTRAN store arrays in different order, so the subscripts
and dimensions have to be reversed.)

> My question is can I access the fortran array above as a double indirection
> + offset, as I would a C array?

No, but then you don't access C arrays that way, either.  There's no double
indirection, since you don't have any pointers to pointers, just a pointer
to an array.

> Is there any way of accessing the array that does not need to know the
> dimensions to get the offset?  [Suggestions like 'do it in fortran' are
> not needed--thanks!!]

No, there is no such way of accessing the array, even in FORTRAN - "do it in
FORTRAN" is, indeed, unhelpful, since you can't do it in FORTRAN either.
The only thing you *can* do in FORTRAN in these cases which you can't do in
C is to declare an array argument with variable dimensions:

	SUBROUTINE SUB(A, M, N)
	REAL A(M, N)
	...

would transliterate into

	void
	sub(a, m, n)
		float (*a)[m][n];
		int m, n;
	{
		...

which isn't legal C.  Such a construct permits you to defer telling "sub"
what the dimensions of "a" are until run time, but you still have to tell it
the dimensions.

	Guy Harris

roy@phri.UUCP (Roy Smith) (09/06/85)

> > Now, in C 2-d arrays are simply an array of pointers to a linear array.
> 
> Slight misconception here.  In C, multi-dimensional arrays are *not*
> arrays of pointers to linear arrays.

	Ah, but they could be if you were willing to do all the memory
allocation and pointer set-up yourself.  I was and I did.  I posted a
little routine called arrayalloc to mod.sources a month or so back which
does just what you are talking about here.  If you are interested, look
through your archives for the following or write me and I'll send you a
copy.

	Subject: run-time memory allocation for multi-dimensional arrays
	Message-ID: <1010@genrad.UUCP>
	Date: 13 Aug 85 11:59:49 GMT
	Mod.sources:  Volume 2, Issue 36
	Submitted by: decvax!allegra!phri!roy (Roy Smith)
-- 
Roy Smith <allegra!phri!roy>
System Administrator, Public Health Research Institute
455 First Avenue, New York, NY 10016

guy@sun.uucp (Guy Harris) (09/10/85)

> > > Now, in C 2-d arrays are simply an array of pointers to a linear array.
> > 
> > Slight misconception here.  In C, multi-dimensional arrays are *not*
> > arrays of pointers to linear arrays.
> 
> 	Ah, but they could be if you were willing to do all the memory
> allocation and pointer set-up yourself.

In which case you'd have an array of pointers to linear arrays, not a
multi-dimensional array.

	Guy Harris