Path: utzoo!attcan!uunet!wuarchive!usc!apple!snorkelwacker!spdcc!ima!haddock!karl From: karl@haddock.ima.isc.com (Karl Heuer) Newsgroups: comp.lang.c Subject: Re: Why does C hate 2d arrays? Message-ID: <16732@haddock.ima.isc.com> Date: 26 May 90 02:01:19 GMT References: <3034@goanna.cs.rmit.oz.au> <16703@haddock.ima.isc.com> <311@ndla.UUCP> Reply-To: karl@haddock.ima.isc.com (Karl Heuer) Organization: Interactive Systems, Cambridge, MA 02138-5302 Lines: 44 In article <311@ndla.UUCP> platt@ndla.UUCP (Daniel E. Platt) writes: >In article <16703@haddock.ima.isc.com>, karl@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@ima.ima.isc.com or harvard!ima!karl), The Walking Lint