g-rh@cca.CCA.COM (Richard Harter) (06/18/88)
In article <5917@aw.sei.cmu.edu> firth@bd.sei.cmu.edu.UUCP (Robert Firth) writes: >The following code, contributed by a C programmer, allocates dynamic >memory for a two-dimensional array: >> For this particuliar >> data structure, the subroutine is basically a one-liner: >> 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: 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. -- In the fields of Hell where the grass grows high Are the graves of dreams allowed to die. Richard Harter, SMDS Inc.
leo@philmds.UUCP (Leo de Wit) (06/21/88)
Sorry this one's so long, I got a bit carried away 8-): --- ------- In article <29605@cca.CCA.COM> g-rh@CCA.CCA.COM.UUCP (Richard Harter) writes: >In article <5917@aw.sei.cmu.edu> firth@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).
g-rh@cca.CCA.COM (Richard Harter) (06/22/88)
In article <517@philmds.UUCP> leo@philmds.UUCP (L.J.M. de Wit) writes:
... Re previous discussion of a proposed substitute for
fortran subscripting
]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:
Sundry examples omitted. The main point of the examples is
that any static dimensioning desired can be set up by properly casting
pointers. This is quite correct. The thing that cannot be done in C
is to have variable dimensioning using C subscripting (as many people
have pointed out you can fake it with a macro which does the address
calculation.)
Offhand, my feeling is that I wouldn't use any of these schemes.
C isn't fortran and vice versa. C doesn't allow
foo(m,n,a)
int m,n;
double a[m][n];
{....}
and that's the way it is. Cute tricks to simulate this just make the
code obscure.
--
In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
Richard Harter, SMDS Inc.
rrr@naucse.UUCP (Bob Rose ) (06/22/88)
In article <517@philmds.UUCP>, leo@philmds.UUCP (Leo de Wit) writes: > 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; > } Close, but ... I assume you are using calloc to zero the array, but the whole world is not a VAX. Try: double **Create2DArray(w,h) register int w,h; { register double **r, *a, **q; register int i; if (((a = (double *)malloc(i = w*h, sizeof(double))) == 0) || ((r = (double **)malloc(h,sizeof(double *))) == 0)) abort(); /* * Zero the array. */ for (*r = a; i--; *a++ = 0.0) ; for (q = r, a = *r; --h; *++q = (a += w)) ; return r; } Just fuel for the fire. -bob
leo@philmds.UUCP (Leo de Wit) (06/26/88)
In article <749@naucse.UUCP> rrr@naucse.UUCP (Bob Rose ) writes: >In article <517@philmds.UUCP>, leo@philmds.UUCP (Leo de Wit) writes: >> [my example using calloc() deleted] >Close, but ... I assume you are using calloc to zero the array, but >the whole world is not a VAX. Try: > > [Bob's example using malloc() deleted] What makes you think calloc() is VAX-specific? I checked with K&R: section 7.9 Storage Management contains calloc(); with Lattice C: had also calloc(). Now sure my ST is fast but would you call it a VAX?? Ultrix has calloc (see man 3 malloc) (and |Ultrix - BSD| < eps); VAX-VMS has calloc (now there's a VAX); on my work calloc is in the ansi.h header file we use for portability (so it should be in the ANSI draft): extern void *calloc(size_t nmemb, size_t size); I think you were mistaken with cfree() which is not as general (VAX-VMS has it). >Just fuel for the fire. > -bob Thanks! So I can light my cigar now 8-). Leo++
sbw@naucse.UUCP (Steve Wampler) (06/27/88)
From article <527@philmds.UUCP>, by leo@philmds.UUCP (Leo de Wit): > In article <749@naucse.UUCP> rrr@naucse.UUCP (Bob Rose ) writes: >>Close, but ... I assume you are using calloc to zero the array, but >>the whole world is not a VAX. Try: >> >> [Bob's example using malloc() deleted] > > What makes you think calloc() is VAX-specific? I checked with K&R: . I'm pretty sure Bob was not worried about calloc() existing, just that it may do the wrong thing. The bit pattern for 0.0 is not all 0 bits on all machines. What's needed is an falloc() (filled alloc()), where the value to fill (and the size, I suppose) are passed as arguments. . . . . .(sigh, inews fodder) -- Steve Wampler {....!arizona!naucse!sbw}
rrr@naucse.UUCP (Bob Rose ) (06/28/88)
In article <527@philmds.UUCP>, leo@philmds.UUCP (Leo de Wit) writes: > I write: > > Leo de Wit writes: > > > [my example using calloc() deleted] > >Close, but ... I assume you are using calloc to zero the array, but ^^^^^ The array was of double!!!!! > >the whole world is not a VAX. Try: > > > > [Bob's example using malloc() deleted] > > What makes you think calloc() is VAX-specific? I checked with K&R: > [ ... its in all the man pages and dpANS ... ] You misunderstood me. (A lot of people have been doing that lately, maybe I need a vacation :-) Calloc is available every where except on systems totally brain damaged. The thing is calloc binary zero's the memory. The array you where zeroing was of type double. Now no where does it say that the internal representation of a double must be binary zero (most machines it is, but NOT all.) This turns out to be one of those hard to find bugs when porting to an odd ball architecture. > >Just fuel for the fire. > Thanks! So I can light my cigar now 8-). > > Leo++ So did I make myself clear or should I buy you a box of cigars for the long battle ahead :^) --bob P.S. I would sure like a chapter and vers if calloc can be used to create an array of zeroed doubles.
leo@philmds.UUCP (Leo de Wit) (06/30/88)
In article <760@naucse.UUCP> rrr@naucse.UUCP (Bob Rose ) writes: [calloc stuff deleted]... |You misunderstood me. (A lot of people have been doing that lately, |maybe I need a vacation :-) Calloc is available every where except on |systems totally brain damaged. The thing is calloc binary zero's the |memory. The array you where zeroing was of type double. Now no where |does it say that the internal representation of a double must be binary |zero (most machines it is, but NOT all.) This turns out to be one of |those hard to find bugs when porting to an odd ball architecture. As a matter of fact, the calloc() came from someone else's article. That person used a calloc for each row of the array and a calloc for the array of pointers to the rows. I didn't even bother to change them to malloc's which I use myself normally; perhaps to make the comparing easier (how's that for an excuse ? ;-). As for initialization, I think it is better to have that as a separate function; there may just be cases in which it is inefficient to first set all values to zero, then fill it with values. || |Just fuel for the fire. || Thanks! So I can light my cigar now 8-). || || Leo++ | |So did I make myself clear or should I buy you a box of cigars for the |long battle ahead :^) | --bob Make it a pipe of peace. And now you did it (to) yourself: you made yourself clear using calloc 8-) (but that's allowed in this case, you being an integer person, not some double-crosser %-). !!leo