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