/* Written by Blair Haukedal 91/09 and placed in the public domain */ /* mdalloc - a multi dimensional array allocator * mdfree - a companion function to mdalloc for freeing storage * synopsis: * void *mdalloc(int ndim, int width, ...); * where: ndim: number of array dimensions * width: size of elements in array * variable args are dimensions of array * returns: n-way indirect pointer to allocated storage * or NULL if insufficient storage * * void mdfree(void *p, ndim); * where: p: pointer to storage obtained by mdalloc * ndim: number of dimensions used in mdalloc * * example: * int ***tip; * tip = mdalloc(3, sizeof(int), 2, 3, 4); * tip will be a triple indirect pointer to a 3 dimensional array * tip[0][0][0] refers to the first int in a contiguous area of * storage that is 2*3*4*sizeof(int) bytes long * tip[0][0] is the address of the first int * memset can be used to initialize array elements as follows: * memset(tip[0][0], 0, 2*3*4*sizeof(int)); * mdfree is used to free storage obtained with mdalloc: * mdfree(tip, 3) * * notes: * - must be compiled with appropriate memory model * - memory is allocated for each dimension for indirect pointers * eg. 3x4x5 array of longs * (assuming 4 byte longs, small mem model) * p = mdalloc(3, sizeof(long), 3, 4, 5) - bytes * 3 pointers allocated for 1st dimension - 6 * 3x4 pointers allocated for 2nd dimension - 24 * 3x4x5 longs allocated for array elements - 240 * total of 270 bytes allocated * - if insufficient memory, nothing will be allocated. * ie. intermediate pointer arrays that were successfully * allocated will be freed. * - the intent of mdalloc is to facilitate dynamic array creation, * it will use more memory than statically declared arrays, and * the required dereferencing will be slower than the use of * statically declared arrays. * - this function assumes that sizeof(char) == 1. */ #include #include static void **md2(int n_units, int ndim, int *dims); static void md3(char ***tip, int n_units, int ndim, int *dims); static int w_units; /* mdalloc: entry point for mdalloc function described above * - reduces variable arg list to fixed list with last arg * represented as pointer to int (array dimensions). * Calls md2 to allocate storage. * Calls md3 to initialize intermediate pointers. * Returns pointer. */ void *mdalloc(int ndim, int width, ...) { va_list argp; int *dims, i; char ***tip; va_start(argp, width); /* allocate storage for variable args (dimensions) */ dims = malloc(ndim*sizeof(int)); if(dims == NULL) return NULL; /* initialize dimensions array for subsequent calls */ for(i=0; i1 && tip) md3(tip, dims[0], ndim-1, &dims[1]); /* init pointers */ free(dims); return tip; } /* mdfree: companion function to mdalloc * frees storage obtained by mdalloc */ void mdfree(void *tip, int ndim) { if(ndim == 1) free(tip); else { mdfree(((void **)tip)[0], ndim-1); free(tip); } } /* md2: allocates storage for n-way indirect pointer arrays * allocates storage for requested array elements */ static void **md2(int n_units, int ndim, int *dims) { char **tip; if(ndim == 1) /* recursed to final dimension - allocate element storage */ tip = malloc(n_units*w_units); else { /* allocate pointer array for dimension n */ tip = malloc(n_units*sizeof(char *)); if(tip) { /* recurse until final dimension */ tip[0] = (char *)md2(n_units*dims[0], ndim-1, &dims[1]); if(tip[0] == NULL) { /* allocate error - fall back up freeing everything */ free(tip); tip = NULL; } } } return (void **)tip; } /* md3: initializes indirect pointer arrays */ static void md3(char ***tip, int n_units, int ndim, int *dims) { int i; for(i=1; i 1) /* not at final dimension - continue to recurse */ md3((char ***)tip[0], n_units*dims[0], ndim-1, &dims[1]); }