home *** CD-ROM | disk | FTP | other *** search
- /*
- * NAME
- * dynamem.3
- *
- * FUNCTION
- * dynamem, dynafree -- multidimensional dynamic array handling
- *
- * SYNOPSIS
- * char *dynamem(pointer, element_size,
- * number_dimensions, dimensions ...)
- * char **pointer;
- *
- * dynafree(pointer)
- * char *pointer;
- *
- * DESCRIPTION
- * dynamem() is the multidimensional analogue to malloc().
- * dynamem allocates a <number_dimensions> dimensional array,
- * whose dimensions are stored in a list starting at <dimensions>.
- * Each array element is of size <element_size>.
- * <pointer> is a pointer with <number_dimensions> levels of
- * indirection to the memory area, on exiting the procedure this
- * will point to the beginning of the array.
- *
- * dynamem() attempts to set up the array required in the same way that
- * it would be set up by the compiler at compile time. Thus
- * a multidimensional dynamically array declared using dynamem()
- * can be used in exactly the same way as a fixed array declared
- * by the compiler.
- *
- * dynafree() is the dynamem analogue to free(). When passed an
- * array previously dynamically declared by dynamem(), and the number
- * of dimensions the function returns this memory to the system.
- *
- * EXAMPLE
- * To declare a 4 dimensional array normally one would code:
- *
- * int array[10][11][12][13];
- *
- * however, this array is then fixed at compile time. This
- * same array can be declared dynamically at run time
- * using the following code:
- *
- * int ****array;
- *
- * array = (int ****) dynamem(&array, sizeof(int),
- * 4, 10, 11, 12, 13);
- *
- * (Note that the number of levels of indirection in the cast
- * is equal to the number of dimensions in the array.)
- * This enables array sizes to be fixed via, for example,
- * command line arguments.
- *
- * SEE ALSO
- * malloc(3)
- *
- * DIAGNOSTICS
- * dynamem() returns NULL if it is unable to allocate sufficient
- * memory for the array.
- *
- * NOTES
- * There is obviously some overhead in the actual
- * setting up of the array; however, this is minimal.
- * On a SUN system when dynamically allocating 2 arrays of 346000
- * unsigned characters and one of the same number of shorts all in
- * two dimensions, the run time of a convolution of a 7x7 Lapacian-
- * Marr filter over an image of size 720 by 480 varied as follows:
- *
- * time convolve -fbfilt -X720 -Y480 -e < bubble2 > test.1
- * 222.0 real 213.4 user 1.6 sys
- *
- * time convolve -fbfilt -e < bubble2 > test.2
- * 225.2 real 212.5 user 2.7 sys
- *
- * which is probably adequate. From this we can see that
- * it takes 1.1 secs for the fixed array to be set up
- * and zeroed and only 0.9 secs for the array to be
- * dynamically declared using dynamem();
- * however, using dynamem() the array is not initialized to
- * 0 and this is the reason for the 0.2 speed increase.
- *
- * This code should really be changed to allocate one extra int
- * location four bytes BEFORE the array itself. Store the number of
- * dimensions in that hidden location.
- *
- * Should be revised to use the stdarg.h variable argument handling
- * methods defined by ANSI C.
- *
- * VERSION
- * 1 Kevin Northover 1988-02-23
- *
- * dynamem was developed by Gareth Waddell at Bristol University, UK
- * and was posted to the UseNet unix user's network.
- * The code is public domain, dynafree bug fixed and
- * debugging macros added by KJEN.
- */
-
- extern char *malloc();
-
- #include "dbug.h" /* Fred Fish DBUG macro package */
-
- char *
- dynamem(p, s, d, d1)
- char **p;
- int s, d, d1;
- {
- int max, /* size of array to be declared */
- *q; /* pointer to dimension list */
- char **r, /* pointer to begining of the array of the
- * pointers for a dimension */
- **s1, *t, *tree; /* base pointer to begining of first array */
- int i, /* loop counters */
- j;
-
- DBUG_ENTER("dynamem");
-
- r = &tree;
- q = &d1; /* first dimension */
- max = 1;
-
- /* for each of the dimensions but the last */
- for (i = 0; i < d - 1; i++, q++) {
- max *= (*q);
- if ( (char *) 0 ==
- (r[0] = malloc((unsigned) max * sizeof (char **))) ) {
- dynafree(tree, d);
- DBUG_RETURN( r[0] );
- }
- DBUG_PRINT("mchk", ("pointer block at address %lx", r[0]));
- r = (char **) r[0]; /* step through to begining of next
- * dimension array */
- }
- max *= s * (*q); /* grab actual array memory */
- if ( (char *) 0 == (r[0] = malloc((unsigned) max)) ) {
- dynafree(tree, d);
- DBUG_RETURN( r[0] );
- }
- DBUG_PRINT("mchk", ("data block at address %lx", r[0]));
-
- /*
- * r is now set to point to the begining of each array so that we can
- * use it to scan down each array rather than having to go across and
- * then down
- */
- r = (char **) tree; /* back to the begining of list of arrays */
- q = &d1; /* back to the first dimension */
- max = 1;
- for (i = 0; i < d - 2; i++, q++) {
- /* we deal with the last array of pointers later */
-
- max *= (*q); /* number of elements in this dimension */
-
- /* scan down array for first and subsequent elements */
- for (j = 1, s1 = r + 1, t = r[0]; j < max; j++) {
- /*
- * modify each of the pointers so that it points to
- * the correct position (sub-array) of the next
- * dimension array. s1 is the current position in the
- * current array. t is the current position in the
- * next array. t is incremented before s is, but it
- * starts off one behind. *(q+1) is the dimension of
- * the next array.
- */
- *s1++ = (t += sizeof (char **) * *(q + 1));
- }
- r = (char **) r[0]; /* step through to begining of next
- * dimension array */
- }
-
- /* max is total number of elements in the last pointer array */
- max *= (*q);
- for (j = 1, s1 = r + 1, t = r[0]; j < max; j++) {
- /* same as previous loop, but different size factor */
- *s1++ = (t += s * *(q + 1));
- }
- DBUG_RETURN(tree); /* return base pointer */
- }
-
- dynafree(r, d)
- char *r;
- int d;
- {
- char **p;
- int i, j;
-
- DBUG_ENTER("dynafree");
-
- /* we need to count the dimensions to guarantee termination before
- * lots of random memory gets stomped -- kjen 880223
- * free in reverse order of allocation
- */
- for ( j = d-1; j >= 0; j-- ) {
- for (p = &r, i=0; p && (i < j); p = (char **) *p, i++) ;
- if ( p ) {
- DBUG_PRINT("mchk", ("freeing block %lx", *p));
- free(*p);
- }
- }
- DBUG_RETURN(0);
- }
-