[comp.lang.c] [not just] Think C: dynamic 2d array allocation

scs@adam.mit.edu (Steve Summit) (04/24/91)

In article <frost.672455128@watop> frost@watop.nosc.mil (Richard Frost) writes:
> unsigned int	**image;	
>	**image = (unsigned int **) malloc(max_el * sizeof(unsigned int *));
>
> [This code was] copied from "Answers to Frequently Asked Questions."
> [It leads] to the compiler error "Illegal pointer/integer combination"
>
> Did I miss-copy?  What's going on here?

There are two problems.  The first is that the sample code in the
FAQ list does not, at that point, remind you to declare malloc
properly.  You must use either the line

	#include <stdlib.h>

or

	extern char *malloc();

depending on whether you have an ANSI or pre-ANSI compiler,
respectively.

(I can't remember whether this was a deliberate omission in the
FAQ list or not.  Since the question is "How do I [use malloc to]
dynamically allocate a multidimensional array?" and not "How do I
use malloc at all?", I may have decided that properly declaring
malloc should have been obvious.  A later question does mention
using <stdlib.h> to declare malloc; this question probably
should, too.)

The second, larger problem is that the code was miscopied, just a
bit, but the difference is crucial.  The fragment in the FAQ list
saves a line (I hate it when textbook authors compress code to
save space, and now I'm doing it) by coalescing the declaration
and initialization of the variable `array':

	int **array = (int **)malloc(nrows * sizeof(int *));

The variable's name is `array'.  *array is what it points to, and
**array is what what it points to points to :-) .  If you want to
separate the declaration and assignment, the assignment would
look like:

	array = (int **)malloc(nrows * sizeof(int *));

because it is the (double) pointer variable `array' to which we
are first assigning.  The next loop

	for(i = 0; i < nrows; i++)
		array[i] = (int *)malloc(ncolumns * sizeof(int));

starts filling in the memory that `array' points to (akin to
*array), and it's not until we start setting individual array
elements (array[i][j] = expr) that we write to the memory that
`array' points to points to (i.e. **array).

I'll grant that the asymmetric appearance of

	int **array = <expr>;

versus

	int **array;
	array = <expr>;

is a bit distracting.  It's something you just have to get used to.

By the way, anyone is free to send me email when there are
questions or problems with the FAQ list.  (This is not a flame;
FAQ list followups have been delightfully infrequent, and
Richard's was not out of line.)

                                            Steve Summit
                                            scs@adam.mit.edu