karl@haddock.ISC.COM (Karl Heuer) (06/15/88)
In article <59@cubsun.BIO.COLUMBIA.EDU> shenkin@cubsun.UUCP (Peter Shenkin) writes: >[What about] > float **matrix( int nrl, int nrh, int ncl, int nch ) >[and its N-dimensional generalization?] > float **array( int Ndim, > int n1l, int n1h, int n2l, int n2h, ..., int nNl, int nNh ) Since normal arrays in C are zero-based, I don't see any reason to specify the lower bounds. If you allocate the entire array (including space for the pointers as well as the contents) in a single chunk, then you don't need all those free_array() routines -- the standard free() will work. I've written it this way. The N-dimensional generalization is incorrectly typed. Since the number of levels of indirection is not known at compile-time, it should be "void *". There's a problem with the lack of generality. You suggest implementing these in triplicate: arrays of integer, float, or double are allowed. What if some other type is desired, e.g. long int, or some random struct? I'd prefer a syntax that expects the type-name as an argument to the macro: float **mtrx = array2d(float, nr, nc); Unfortunately, on some architectures the only way to implement this correctly requires a (minor) hook in the compiler. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint Followups to comp.lang.c only.
chpf127@ut-emx.UUCP (J. Eaton) (06/15/88)
In article <4556@haddock.ISC.COM> (Karl Heuer) writes: > In article <59@cubsun.BIO.COLUMBIA.EDU> (Peter Shenkin) writes: > >[What about] > > float **matrix( int nrl, int nrh, int ncl, int nch ) > >[and its N-dimensional generalization?] > > float **array( int Ndim, > > int n1l, int n1h, int n2l, int n2h, ..., int nNl, int nNh ) > > Since normal arrays in C are zero-based, I don't see any reason to > specify the lower bounds. What if I decide I would like to have negative as well as positive (or zero) indices for arrays? Standard Fortran allows this. Doesn't C? > Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint J. Eaton UT Dept of Chemical Engineering Walking Fortran 77 Lint (well, as close as there is around here anyway :-).
chris@mimsy.UUCP (Chris Torek) (06/15/88)
In article <3342@ut-emx.UUCP> chpf127@ut-emx.UUCP (J. Eaton) writes: >What if I decide I would like to have negative as well as positive >(or zero) indices for arrays? > >Standard Fortran allows this. Doesn't C? Well, yes and no. You can portably use nonzero array origins if and only if the zero point is contained within the array. If not, you get into some shady areas, where the code will work on most machines and in most cases, but is not guaranteed. To get an array of type `ty' that ranges from LOW to HIGH, where LOW <= 0 and HIGH > 0, write ty actual_array[HIGH-LOW]; #define array (&actual_array[-LOW]) ... work with array[k], where LOW <= k < HIGH ... or ty *actual_ptr, *ptr; actual_pointer = (ty *)malloc((HIGH-LOW) * sizeof(ty)); if (actual_pointer == NULL) ... no memory; ptr = actual_ptr - LOW; /* nb. LOW nonpositive, so ptr>=actual_ptr */ ... work with ptr[k], where LOW <= k < HIGH ... free(actual_ptr); /* * N.B.: this can be done with a single pointer. * If cheating with a positive LOW, the result * might happen to == NULL. */ This code generally works even with LOW positive, but the address computed for `ptr' above is outside of the address space returned by malloc(); whether this causes a fault or other misbehaviour is implementation-dependent. If it happens to be equal to (ty *)NULL, the runtime system might `helpfully' catch it. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
hg@mas1.UUCP (Heinrich Gantenbein) (06/16/88)
In article <4556@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes: >In article <59@cubsun.BIO.COLUMBIA.EDU> shenkin@cubsun.UUCP (Peter Shenkin) writes: >>[What about] >> float **matrix( int nrl, int nrh, int ncl, int nch ) >>[and its N-dimensional generalization?] >> float **array( int Ndim, >> int n1l, int n1h, int n2l, int n2h, ..., int nNl, int nNh ) > > >[stuff deleted] There is an excellent article about dynamic allocated arrays in C puplished in the June issue of Computer Language on page 83. (Volume 5, Number 6) Heinrich Gantenbein {...}pyramid!voder!mas1!hg {...}codas!mas1!hg
jjr@ut-emx.UUCP (Jeff Rodriguez) (06/16/88)
In article <4556@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes: >If you allocate the entire array (including space for the pointers as well as >the contents) in a single chunk, then you don't need all those free_array() >routines -- the standard free() will work. I've written it this way. Quite true. Another benefit is that the one can use one call to fread() to read a binary image from a file directly into one of these arrays. If each row is allocated with a separate call to malloc(), then the resulting array must be filled one row at a time. Jeff Rodriguez jjr@emx.utexas.edu
gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/16/88)
In article <3342@ut-emx.UUCP> chpf127@ut-emx.UUCP (J. Eaton) writes: > What if I decide I would like to have negative as well as positive > (or zero) indices for arrays? > Standard Fortran allows this. Doesn't C? Sure it does, so long as there is a valid object at the referenced location. In fact I'm just about to change some application code's dynamic array allocation so that [-1] will be a valid offset.
gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/16/88)
In article <3365@ut-emx.UUCP> jjr@ut-emx.UUCP (Jeff Rodriguez) writes: >In article <4556@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes: >>If you allocate the entire array (including space for the pointers as well as >>the contents) in a single chunk, then you don't need all those free_array() >>routines -- the standard free() will work. I've written it this way. > >Quite true. Another benefit is that the one can use one call to fread() >to read a binary image from a file directly into one of these arrays. >If each row is allocated with a separate call to malloc(), then the >resulting array must be filled one row at a time. Karl's point is that the "row vector" can be contiguous with the MxN data area. That is indeed a nice idea, and I think I'll change some of our applications to do this. fread() can fill the data area, but then people like me who've been allocating separate row vector and MxN data areas could have done that anyway. Separate allocations for each row really would be pretty dumb, unless several rows might be unneeded (I have an application like that, too).
chris@mimsy.UUCP (Chris Torek) (06/16/88)
>>In article <4556@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) >>writes: >>>If you allocate the entire array (including space for the pointers as well as >>>the contents) in a single chunk, then you don't need all those free_array() >>>routines -- the standard free() will work. I've written it this way. The problem with this is alignment. size_t i, n_rows, n_cols; void *p; void *malloc(size_t size); ty *data_area, **row_area; p = malloc(n_rows * sizeof(ty *) + n_rows * n_cols * sizeof (ty)); if (p == NULL) ... row_area = p; data_area = (ty *)(row_area + n_rows); for (i = 0; i < n_rows; i++) row_area[i] = data_area + i * n_cols; This allocates the row vectors and the array, and sets up the row vectors to point to the rows. But if `ty' is `double', there is no guarantee that *data_area will not trap---for instance, if n_rows is odd and sizeof(double *)==4 and sizeof(double)==8 and doubles must be aligned on an eight-byte boundary. In article <8099@brl-smoke.ARPA> gwyn@brl-smoke.ARPA (Doug Gwyn) writes: >Karl's point is that the "row vector" can be contiguous with the MxN data >area. That is indeed a nice idea, and I think I'll change some of our >applications to do this. To do it you need to be able to align `data_area' above, which is why we need some sort of standard <align.h> header. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
karl@haddock.ISC.COM (Karl Heuer) (06/18/88)
In article <11989@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >>>In article <4556@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) >>>writes [that by using one big malloc for both the row vectors and the data >>>area makes it simpler to deallocate the thing] > >The problem with this is alignment. This is correct; if there are objects with stricter alignment than pointers, you may need to insert a shim. On any individual machine this is easy, but without an <align.h> there's no absolute guarantee. (But I'd bet aligning to sizeof(double) would work on all current implementations. This can be done without mucking around with the pointer format, since the base pointer returned by malloc() is already aligned.) In any case, the use is portable even if the implementation details are not. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/18/88)
In article <11989@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >To do it you need to be able to align `data_area' above, True. >which is why we need some sort of standard <align.h> header. Nah, the application can do this itself (it might be overly conservative, but the amount of wasted space would be small). (Hint: use a union.)