/* 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
* 3pointers allocated for 1st dimension - 6
* 3x4 pointers allocated for 2nd dimension - 24
* 3x4x5longs 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
#include "snparray.h"
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; i dims[i] = va_arg(argp,int); w_units = width;/* global used by md2 and md3 */ /* allocate required pointer and array element storage */ tip = (char ***)md2(dims[0], ndim, &dims[1]); if(ndim>1 && 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 { if(ndim == 1) /* final dimension - must scale by element width */ tip[i] = (char **)((char *)tip[0] + i*dims[0]*w_units); else /* intermediate dimension - scale by pointer size */ tip[i] = tip[0] + i*dims[0]; } if(ndim > 1) /* not at final dimension - continue to recurse */ md3((char ***)tip[0], n_units*dims[0], ndim-1, &dims[1]); }