"Dynamic Allocation of 2-D Arrays"

Dave Hampton daveh at phred.UUCP
Thu Sep 15 01:36:31 AEST 1988


  Thanks to all who replied to my query on the best way to dynamically
allocate multi-dimensional arrays.  Karl's note incorporated all of the
other suggesttions which I received, so I am posting it (with permission)
as a summary of the techniques required.

------------------------------------------------------------------------

>The closest that I have been able to come (for a 100 by 100 square array
>of integers) is:
>   int (* array_name)[100];
>   array_name = (int *) calloc (1000, sizeof(int));
>   for (x=0; x<ROW; x++) for (y=0; y<COL; y++) array_name[x][y] = x * y;
>   free (array_name);

First, a 100x100 array has 10000 elements, not 1000.

Now, assuming that the column dimension is a constant expression, you're
almost right.  The type of an object looks just like the declaration with the
name removed, so the type of `array_name' is `int (*)[100]'.  The type `array
of 100 ints' is denoted `int [100]'.  What you want is:
   array_name = (int (*)[100])calloc(100, sizeof(int [100]));
This could also be done with
   array_name = (int (*)[100])calloc(10000, sizeof(int));
but I think the former is clearer.

If the column dimension isn't constant, you can't do this.  You could instead
use a pointer to a pointer rather than a pointer to an array (and despite what
anyone tells you, pointers and arrays are not the same thing in C).  This
requires a bit more work to build and destroy, but can still be accessed using
normal subscript notation:
   int **array_name;
   array_name = (int **)calloc(nrows, sizeof(int *));
   for (x=0; x<nrows; ++x) array_name[x] = (int *)calloc(ncols, sizeof(int));
   for (x=0; x<nrows; ++x) for (y=0; y<ncols; ++y) array_name[x][y] = x * y;
   for (x=0; x<nrows; ++x) free(array_name[x]);
   free(array_name);

As a variation on this, it's also possible to combine the allocations so that
the whole mess can be destroyed with a single free():
   #define ALIGN 8 /* implementation-dependent */
   int **array_name;
   int offset = (nrows*sizeof(int *)+ALIGN-1)/ALIGN*ALIGN;
   array_name = (int **)malloc(offset + nrows*ncols*sizeof(int));
   for (x=0; x<nrows; ++x)
     array_name[x] = (int *)((char *)array_name+offset+x*ncols*sizeof(int));
   for (x=0; x<nrows; ++x) for (y=0; y<ncols; ++y) array_name[x][y] = x * y;
   free(array_name);
(The constant ALIGN is technically implementation-dependent, but the value 8
suffices for any implementation I know of.)

Finally, if you don't mind having to do the subscript calculation with a
macro, you can use the simpler mechanism:
   #define array_name(x,y) (_array_space[(x)*(ncols)+(y)])
   int *_array_space;
   _array_space = (int *)calloc(nrows*ncols, sizeof(int));
   for (x=0; x<nrows; ++x) for (y=0; y<ncols; ++y) array_name(x,y) = x * y;
   free(&array_name(0,0));

This is more than you asked for, but I wasn't sure how much generality you
needed.

Karl W. Z. Heuer (ima!haddock!karl or karl at haddock.isc.com), The Walking Lint


-- 
Reply to:  uiucuxc!tikal!phred!daveh {Dave Hampton}
Addr:      Research Division, Physio-Control Corp.
           P.O. Box 97006
           Redmond, WA  98073-9706



More information about the Comp.lang.c mailing list