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