1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
/* 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 <stdarg.h>
#include <stdlib.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<ndim; 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<n_units; 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]);
}
|