A BETTER way to do Multidimensional arrays in C

Steve White srw at lasspvax.UUCP
Sun Jan 13 14:22:29 AEST 1985


A few months ago I realized there was a better way to do multidimensional
arrays in C.  This way is not new; in fact, it is discussed on page 110
of Kernighan and Ritchie.  But after reading the discussions in net.lang.c
concerning the subject of multidimensional arrays I decided a lot of 
people might not be aware of it or might not appreciate its advantages.
Here's how it works.

The following program illustrates the idea (go ahead, try it!):

main()
	{
	double	**array;		/* This will be a 10 x 12 array */
	int i;

	array = (double **) calloc(10,sizeof(double *)); 	
	/* Number of rows = 10 */

	for	(i = 0; i < 10; i++)
		array[i] = (double *) calloc(12,sizeof(double));  
	/* Number of columns = 12 */

	array[2][3] = 3.14159265359;
	array[4][5] = 2.71828182846;
	anyfunc(array);
	}

anyfunc(a)
double **a;
	{
	printf("%.14g  %.14g\n",a[2][3],a[4][5]);
	}

We first allocate space for an array of pointers, the length of which is
the number of rows.  Then each of these pointers is set to point to 
enough space for one row of the array. Once this is done, then we can
pretend we have a regular 2-dimensional array, except that we never have
to specify its dimensions to any subroutines that use it.

There are a couple of DISADVANTAGES to the above method:

	1. It uses slightly more storage.

	2. You have to initialize the pointers, as in the above program.

It has, however, lots more ADVANTAGES:

	1. All storage allocation can be done dynamically.

	2. Subroutines don't need to know the dimensions of the array to
	access its elements.

	3. Non-rectangular arrays are as easy as rectangular.

	4. The indices do not have to start at zero! Say we wanted our
	indices to start at 1 instead of 0 in the above program (as in
	Fortran). Then the initialization would be changed to

	array = (double **) calloc(10,sizeof(double *)) - 1; 	
	for	(i = 1; i <= 10; i++)
		array[i] = (double *) calloc(12,sizeof(double)) - 1;  

	5. It is FASTER than the standard way (since there is no multiplication
	needed to calculate the address).

To test the relative speeds of this way and the standard way, I ran the
following programs:

/* Old way */
main()
	{
	double	array[200][200];
	register int i, j, l;

	for	(l = 0; l < 10; l++)
		for	(i = 0; i < 200; i++)
			for	(j = 0; j < 200; j++)
				array[i][j] = array[j][i];
	}


/* New way */
main()
	{
	double	**array;
	register int i, j, l;

	array = (double **) calloc(200,sizeof(double *)); 	
	for	(i = 0; i < 200; i++)
		array[i] = (double *) calloc(200,sizeof(double));  

	for	(l = 0; l < 10; l++)
		for	(i = 0; i < 200; i++)
			for	(j = 0; j < 200; j++)
				array[i][j] = array[j][i];
	}

The "Old way" took 22 sec. on our Vax 11/750, while the "New way"
took 17.4 sec. (When the optimizer was invoked with -O, the times were
21.4 and 16.2 sec., for the old and new ways, respectively.)

I think this way of handling multidimensional arrays is definitely
superior to the standard way, at least where speed and flexibility
are important.
								Hoping this was useful to you
								(or at least interesting),

								Steve White
								Cornell Univ. Dept. of Physics



More information about the Comp.lang.c mailing list