Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!cs.utexas.edu!uunet!bywater!scifi!ndla!platt From: platt@ndla.UUCP (Daniel E. Platt) Newsgroups: comp.lang.c Subject: Re: Why does C hate 2d arrays? Summary: Why not? Message-ID: <311@ndla.UUCP> Date: 25 May 90 15:54:43 GMT References: <3034@goanna.cs.rmit.oz.au> <16703@haddock.ima.isc.com> Lines: 86 In article <16703@haddock.ima.isc.com>, karl@haddock.ima.isc.com (Karl Heuer) writes: > In article <3034@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: > >There is, however, a silver lining in that cloud. All you have to do is to > >write your own array allocator which returns a pointer to a single block of > >(Nrows pointers then alignment padding then Nrows*Ncols data). > > 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. (This is why I dropped the function from my private > library.) > I'm not sure I understand the problem... How about: void **alloc2(nrows, ncols) int nrows, ncols; /* ncols includes size info */ { int i; void **tmp; if((tmp = (void **)malloc(nrows * sizeof(void *))) == NULL){ /* do something about this problem */ } for(i = 0; i < nrows; i++) if((tmp[i] = (void *)malloc(ncols)) == NULL){ /* do something about this problem.. need to de-allocate what was allocated */ } return tmp; } If you're not using ANSI-C, then you can replace all the 'void's with 'char's and it will work just fine with appropriate type-casting. My documentation on malloc indicates that "malloc returns a pointer to a block of at least 'size' bytes suitably aligned for any use", which implies that all you'd need to do in a structure containing doubles is make sure that there were nice allignment paddings in the structures.... I'm not sure what's wrong with the above approach. I've written lots of nice library functions for my use (things like fft's, matrix inversion and diagonalization, &c) around things like this, and I've had no complaints. Further, these routines can be used to handle arrays with weird shapes... Most of the semantics (what a, a[] and a[][] mean) is pretty much the same at the code level anyway -- it does mean something different at the assembler level, and the declarations look different -- when comparing doubly dimensioned arrays with pointer arrays of pointers to arrays. Or did I miss the point? > It's impossible for a user to write it in portable C. Is the above not portable? > But it's relatively > easy for the *implementor* to provide it, since he can add compiler hooks as > necessary. On a vaxlike architecture this would simply be implemented as > #define malloc2d(nr, nc, T) ((T **)alloc2((nr), (nc)*sizeof(T))) > where alloc2() is the function mentioned earlier. On a word-addressed > architecture with two or more flavors of pointers, you use > #define malloc2d(nr, nc, T) ((T **)_alloc2((nr), (nc)*sizeof(T), \ > __whichpointer(T))) > where __whichpointer() is some mapping from types to small integers to encode > the information about pointers. (alignof() might suffice.) Then the actual > function simply does > switch (wp) { > case __whichpointer(char): > ((char **)vec)[i] = (char *)&block[i*nc*sz]; break; > case __whichpointer(int): > ((int **)vec)[i] = (int *)&block[i*nc*sz]; break; > } > I thought malloc() was supposed to handle allignment problems by starting blocks on the largest appropriate boundary. Dan Platt PS... I'm not trying to be argumentative or contrary -- its just that if I've missed a fine point of C, I'd like to know about it...