Variable dimensioning in fortran

Leo de Wit leo at philmds.UUCP
Wed Jun 22 00:12:57 AEST 1988


Sorry this one's so long, I got a bit carried away 8-):
                                  --- -------

In article <29605 at cca.CCA.COM> g-rh at CCA.CCA.COM.UUCP (Richard Harter) writes:
>In article <5917 at aw.sei.cmu.edu> firth at bd.sei.cmu.edu.UUCP (Robert Firth) writes:
>>> double **Create2DArray(w,h)
>>> int w,h;{ double **r;
>>> for(r=(double**)calloc(h,sizeof(*r));h-->0;r[h]=(double*)calloc(w,sizeof(**r)));
>>> return(r);}
>
>>Any Fortran programmer who seriously proposes to convert to C would, in
>>my opinion, be advised to study this example very carefully.  Verbum
>>sapienta sufficit.
>
>	This little trick is all very well, but it does not reproduce the
>fortran facility for variable dimensioning, and it does matter.  The above
>yields an array of arrays.  Consider the following:

The above C code is not adequate for handling flat arrays; the 2 * 5
elements should be allocated as one chunk, with the r[0], r[1], ...
pointing into it, as I explained in a previous article. I'll repeat
that code here for clearness (and removed the errors; this one will
work 8-):

double **Create2DArray(w,h)
int w,h;
{
    double **r, *a;

    a = (double *)calloc(w * h, sizeof(double));
    r = (double **)calloc(h,sizeof(double *));
    for ( ; --h >= 0; r[h] = a + w * h) ;
    return r;
}

This approach has, besides the array being contiguous, as a benifit
that only two allocations are needed. The array can be handled both by
vectoring:  r[0], r[1], ... and by using the flat array pointed to by
r[0]. Now for your example:

>	real a(2,5)
>	call foo(a)
>	....
>	subroutine foo(a)
>	real a(10)
>	...
>
>In this example a is originally allocated as an array of 10 contiguous
>locations; subroutine foo takes advantage of that knowledge.  The point
>of fortran subscripting rules is that the dimension structure can be
>changed dynamically.

And so for C subscripting rules. Watch me:

extern double **Create2DArray();

static void foo1(), foo2(), foo3(), fooall();

main()
{
    double **a = Create2DArray(2,5);
    int i;

    foo1(a[0]); foo2(a[0]); foo3(a[0]); fooall(a[0]);
    for (i = 0; i < 10; i++) {
        printf("%d: %f\n",i,a[0][i]);
    }
}

static void foo1(a) /* now using it as a 1 dim array : a[10] */
double *a;
{
    a[7] = 3.0;
}

static void foo2(a) /* now using it as a 2 dim array : a[2][5] */
double (*a)[5];
{
    a[1][3] = 45.3;
}

static void foo3(a) /* now using it as a 3 dim array : a[2][2][2] */
double (*a)[2][2];
{
    a[1][1][0] = 2.0;
}

static void fooall(a) /* Full Organ: C major: the previous altogether */
double *a;
{
    double *a1 = a; /* just for symmetry */
    double (*a2)[5] = (double (*)[5])a;
    double (*a3)[2][2] = (double (*)[2][2])a;

    a1[7] = 3.0;
    a2[1][3] = 45.3;
    a3[1][1][0] = 2.0;
}

Like to see you do the last trick in Fortran! Note that it is both
elegant and efficient (although a Fortran programmer will have trouble
reading the declarations, the rest of the code is straightforward); the
same array can be accessed with whatever dimension you like.  The only
trouble is that even experienced C programmers often don't know this
stuff, mostly because they didn't need it.

If you would also like to have the vectors available, pass a itself as
parameter, and use a[0], a[1] for vectors; for example, the header of
fooall() would then be:

static void fooall(a) /* Full Organ: C major: the previous altogether */
double **a;
{
    double *a1 = a[0]; /* just for symmetry */
    double (*a2)[5] = (double (*)[5])a[0];
    double (*a3)[2][2] = (double (*)[2][2])a[0];

If you don't need the vectors (and probably you won't, seeing the
above), Create2DArray could be further simplified; the r[h] vectors are
left out and Create2DArray reduces to a macro:

#define Create2DArray(w,h) (double **)calloc((w)*(h),sizeof(double))

and then, why not, to avoid difficult declarations:

#define Declare1DAcast(a1,a)     double *a1 = (a)
#define Declare2DAcast(a2,a,m)   double (*a2)[(m)] = (double (*)[(m)])(a)
#define Declare3DAcast(a3,a,m,n) double (*a3)[(m)][(n)] = \
                                                     (double (*)[(m)][(n)])(a)
etc. Enjoy!

    Leo.

                        (C me, feel me, touch me, heel me).



More information about the Comp.lang.c mailing list