home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Elysian Archive
/
AmigaElysianArchive.iso
/
prog
/
c
/
dyname.lha
/
dynamem.c
next >
Wrap
C/C++ Source or Header
|
1990-06-04
|
6KB
|
201 lines
/*
* 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);
}