/* +++Date last modified: 05-Jul-1997 */

/*

AMALLOC - multi-dimensional malloc()

Allocates a multidimensional array dynamically, at runtime, so that

1: its elements can be accessed using multiple indirection

2: it can be deallocated using a call to the standard free() function

Note: On PC's the max array size is 64K

Paul Schlyter, 1992-02-09. Released to the public domain.

*/

#include 

#include 

#include 

#include "snparray.h"

#define MAXDIMS 5 /* Defines the maximum number of dimensions */

#define MAXSIZE ((size_t) -1L) /* Maximum size of array */

void *amalloc( int esiz, void *initval, int dims, ... )

/*

* Input:esiz size of each array elements, as given by sizeof

*initval pointer to initial value. NULL ==> zero fill

*dims number of dimensions: 1..MAXDIMS (5)

*... number of elements in each dimension (int's)

*

* Returns: NULLerror: out of memory, or illegal parameters

*otherwise base pointer to array

*/

    {

    unsigned int dim[MAXDIMS], accdim[MAXDIMS];

    va_list ap;

    int i, j;

    long int totsiz;

    void **q;

    char *p, *r, *s;

    if (dims < 1 || dims > MAXDIMS)

    return NULL;

    memset(dim, 0, sizeof(dim)); /* Read dimension numbers */

    memset(accdim, 0, sizeof(accdim));

    va_start(ap, dims);

    dim[0] = accdim[0] = va_arg(ap,int);

    for (i = 1; i < dims; i++)

        {

        dim[i] = va_arg(ap,int);

        accdim[i] = accdim[i-1] * dim[i];

    }

    va_end(ap);

    /* Compute total array size */

    totsiz = esiz * accdim[dims-1];/* Data size */

    for (i = 0; i < dims - 1; i++ )/* Add space for pointers */

    totsiz += sizeof(void *) * accdim[i];

    if (totsiz > MAXSIZE) /* Exit if totsiz too large */

    return NULL;

    p = malloc((size_t) totsiz); /* Allocate memory */

    if (p == NULL)/* Out-of-memory*/

    return NULL;

    memset(p, 0, (unsigned int) totsiz); /* Zero out allocated memory */

    q = (void **) p;

    if (dims == 1)

    r = (char *) q + esiz * accdim[0];

    for (i = 1; i < dims; i++)/* Fill in pointers */

        {

        int siz;

        int accd = accdim[i-1], d = dim[i];

        siz = i == dims-1 ? esiz : sizeof(void *);

        r = (char *) q + sizeof(void *) * accd;

        for (j = 0; j < accd; j++)

            {

            *q++ = r;

            r += siz * d;

        }

    }

    if (initval != NULL)

        {

        for (s = (char *) q; s < r; s += esiz)

        memcpy(s, initval, esiz);

    }

    return p;

} /* amalloc */

#ifdef TEST/* Test program */

#include 

main()

    {

    static char init_d[8] = { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF };

    int init_i = 0x1111;

    double *a= amalloc( sizeof(double), init_d, 1, 4 );

    double **b = amalloc( sizeof(double), init_d, 2, 4, 5 );

    double ***c = amalloc( sizeof(double), init_d, 3, 4, 5, 6 );

    int ***d = amalloc( sizeof(int), &init_i, 3, 4, 5, 6 );

    int i, j, k;

    for (i = 0; i < 4; i++)

    for (j = 0; j < 5; j++ )

    for (k = 0; k < 6; k++ )

    d[i][j][k] = (i * 256) + (j * 16) + k;

    a = a, b = b, c = c;

    return 0;

}

#endif /* TEST */