Why does C hate 2d arrays?

Karl Heuer karl at haddock.ima.isc.com
Sat May 26 12:01:19 AEST 1990


In article <311 at ndla.UUCP> platt at ndla.UUCP (Daniel E. Platt) writes:
>In article <16703 at haddock.ima.isc.com>, karl at haddock.ima.isc.com (Karl Heuer) writes:
>>Yes, ideally one should be able to write
>>	foo_t **p = (foo_t **)alloc2(nrows, ncols * sizeof(foo_t));
>>	p[i][j] = f;
>>for arbitrary type foo_t.  Unfortunately, it is impossible to portably write
>>a single function, since it has no way to know the type of pointer to use
>>for the dope vectors.
>
>I'm not sure I understand the problem...
>[Example code that appears to solve the problem]
>	... tmp = (void **)malloc(nrows * sizeof(void *));
>	... tmp[i] = (void *)malloc(ncols); ...
>Is the above not portable?

Afraid not.  It fails on word-addressible machines, if `foo_t *' and `void *'
have different internal formats.  The value stored in tmp[i], despite being
maximally aligned, is still a char pointer; but it eventually gets referenced
(via p[i]) as if it were a word pointer.

For an extreme example, suppose that sizeof(foo_t *) is 2 but sizeof(void *)
is 4.  Then the call alloc2(2, 1*sizeof(foo_t)) contiguously allocates two
four-byte cells (each of which it initializes to a pointer to FOOSIZE
additional bytes, which we don't care about for now) and returns a pointer to
the eight-byte block.  The caller casts this to (foo_t **) and stores it in p,
then attempts to reference p[1][0].  But since p is declared to be a pointer
to a `foo_t *', it sees the eight-byte block as four two-byte chunks; the
reference to p[1] will actually fetch bytes 2-3 of the block, which isn't even
in the right section.  (To get the correct answer you'd have to fetch bytes
4-7 and convert them from char-pointer to word-pointer.)

(You don't have to have different sized pointers to get this effect, but it
makes it easier to illustrate.)

The solutions are:
[0] Forget it
[1] Limit yourself to vaxlike architectures
[2] Make the function handle some specific type instead of being generic
    (i.e. write one such function for each type that you might want)
[3] Change the specs to be
	void **p = alloc2(nrows, ncols * sizeof(foo_t));
	((foo_t *)p[i])[j] = f;

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



More information about the Comp.lang.c mailing list