Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
mallocNd.c
Go to the documentation of this file.
1 /*
2 ** Author: James Painter
3 ** Purpose: Allocate memory for an N-d array.
4 **
5 ** Copyright (c), 1988 GRAIL, University of Washington
6 **
7 ** $Revision: 3.0.1.1 $
8 ** $Date: 1992/04/30 14:10:24 $
9 ** $Locker: $
10 ** $Log: mallocNd.c,v $
11 ** Revision 3.0.1.1 1992/04/30 14:10:24 spencer
12 ** patch3: remove lint
13 **
14 ** Revision 3.0 1992/01/23 16:24:19 spencer
15 ** Initial revision.
16 **
17  * Revision 1.1 89/02/08 12:48:33 jamie
18  * Initial revision
19  *
20 */
21 
22 /*
23 ** Synopsis:
24 ** extern char *mallocNd();
25 ** 'SomeDataType' *...*A;
26 **
27 ** A = ('SomeDataType' *...*) mallocNd( nDim, Dims, sizeof('SomeDataType'))
28 ** where 'SomeDataType' is the data type of the array elements
29 
30 ** *...* is a string of nDim *'s.
31 ** nDim is the number of dimensions (unsigned int)
32 ** Dims[] contains the size of each dimension (left-to-right)
33 ** (unsigned ints)
34 **
35 ** Reference values in A as though it was a compile-time 'nDim'-d array
36 ** e.g. A[i][j][k], for a 3-d array.
37 **
38 ** Free by calling free(A);
39 **
40 ** More information and an example follow.
41 */
42 
43 /*
44  ** MallocNd allocates memory for an N-d array. The array is stored
45  ** contiguously (for linear access) but may be referenced through an
46  ** indirection table which is returned. If not enough memory is available
47  ** NULL is returned.
48  **
49  ** E.g. if you want a 10x20x30 3-d array of doubles then:
50  **
51  ** static unsigned int Dims[3] = { 10, 20, 30 };
52  ** double ***A = (double ***) (mallocNd( 3, Dims, sizeof(double) ));
53  **
54  ** Elements of A can be referenced as A[i][j][k] as you would for an
55  ** ordinary 3-d array. The base address of A can be found by:
56  ** &(A[0][0][0]) or alternatively, just A[0][0]. Note that A itself is
57  ** actually the address of the (double) indirection table; A[i] is
58  ** the address of a single indirection table; and A[i][j] is the address
59  ** of one row of data.
60  **
61  ** Note that there is some space overhead for the indirection table.
62  ** It is minimized if the dimensions are non-decreasing. I.e.
63  ** Dims[0] <= Dims[1] <= Dims[2] ...
64  **
65  ** There is a simple but complete example below (look for #ifdef TEST)
66  */
67 
68 /* Imports */
69 #include <stdio.h>
70 #include <string.h>
71 #include <stdlib.h>
72 
73 /* Forward declarations */
74 char *BuildIndirectionTable();
75 
76 
77 /* ------------------------------------------------------------------------ */
78 /*
79 ** A simple test case and example of mallocNd use.
80 */
81 
82 #ifdef TEST
83 main()
84 {
85  int i, j, k, l;
86  static unsigned Dims[5] = { 1, 2, 3, 4, 5 };
87  double *****A, *B, val;
88  extern char *mallocNd();
89 
90  /* A will be a 5-d */
91  A = (double *****) mallocNd( 5, Dims, sizeof(double) );
92  if (A == NULL)
93  {
94  fprintf( stderr, "No memory!");
95  abort();
96  }
97 
98  /* Fill with values so that the i'th dimension index is reflected in the
99  ** i'th base 10 digit of the value.
100  */
101  for(i=0; i<2; i++)
102  for(j=0; j<3; j++)
103  for(k=0; k<4; k++)
104  for(l=0; l<5; l++) {
105  val = l + 10*(k + 10*(j + 10*i));
106  A[0][i][j][k][l] = val;
107  }
108 
109 
110 
111  /* Print the array in linear order (tests that the array is really
112  ** contiguous).
113  */
114  B = &(A[0][0][0][0][0]);
115  for(i=0; i<120; i++) {
116  printf( "%6.0f ", B[i] );
117  if ((i %10) == 9) putchar('\n');
118  }
119 }
120 
121 #endif
122 /* ------------------------------------------------------------------------ */
123 
124 
126  unsigned int nDim; /* The number of dimensions */
127  unsigned int Dims[]; /* The size of each dimension (left-to-right) */
128  unsigned int sizeofelt; /* The number of bytes for each element */
129 {
130  int i;
131  char *ptr, *tableBase, *arrayBase, *nextFreeArray, *nextFreeTable;
132  unsigned int arrayBytesNeeded, tableBytesNeeded, dimProduct, slop;
133 
134  /* Count up the space needed for the indirection tables.
135  ** It's sizeof(pointer) * Dim[0] * ( 1 + Dim[1] * ( 1 + Dim[2] ... ))
136  */
137  tableBytesNeeded = 0;
138  dimProduct = 1;
139  for(i=0; i<nDim-1; i++)
140  {
141  dimProduct *= Dims[i];
142  tableBytesNeeded += dimProduct*sizeof(char *);
143  }
144 
145  /* Add in extra space to force alignment of the array */
146  slop = (tableBytesNeeded % sizeofelt);
147  if (slop != 0)
148  slop = sizeofelt - slop;
149 
150  /* Add in the space for the array itself */
151  dimProduct *= Dims[i];
152  arrayBytesNeeded = dimProduct*sizeofelt;
153 
154  /* Get the memory for the whole thing */
155  ptr = malloc( tableBytesNeeded + slop + arrayBytesNeeded );
156  if (ptr == NULL) return (char *) NULL;
157 
158  /* Set up the base address of the actual array and the indirection table */
159  tableBase = ptr;
160  arrayBase = ptr + slop + tableBytesNeeded;
161 
162  /* Set up the next free pointers for the table space and the array space */
163  nextFreeTable = tableBase;
164  nextFreeArray = arrayBase;
165 
166  /* Build the indirection tables recursively */
167  (void) BuildIndirectionTable( nDim, Dims, (char ***)&nextFreeTable,
168  &nextFreeArray, sizeofelt );
169 
170  /* Do a sanity check to be sure we haven't run off the end of the allocated
171  ** memory. Not strictly needed but here for robustness and debugging.
172  */
173  if (nextFreeTable != arrayBase - slop ||
174  nextFreeArray != ptr + tableBytesNeeded + slop + arrayBytesNeeded)
175  {
176  fprintf( stderr, "Error in mallocNd! Memory overwrite." );
177  abort();
178  }
179  return(char *) tableBase;
180 }
181 
182 
183 
185  sizeofelt )
186  unsigned nDim;
187  unsigned Dims[];
188  char ***nextFreeTable, **nextFreeArray;
189  unsigned sizeofelt;
190 {
191  int i;
192  char *ReturnValue, **table;
193 
194  if (nDim == 1) { /* Base case, indirection table unneeded */
195  ReturnValue = *nextFreeArray;
196  *nextFreeArray += sizeofelt * Dims[0];
197  } else {
198  /* Allocate the 1'st level indirection table and fill it in
199  ** calling ourselves recursively for the others.
200  */
201  table = *nextFreeTable;
202  *nextFreeTable += Dims[0];
203  for(i=0; i<Dims[0]; i++)
204  {
205  table[i] = BuildIndirectionTable( nDim-1, Dims+1, nextFreeTable,
206  nextFreeArray, sizeofelt );
207  }
208  ReturnValue = (char *) table;
209  }
210  return ReturnValue;
211 }
212 
213 
214 /*
215 ** Special case for 2-d arrays
216 */
217 char *
219 int n, m, sizeofelt;
220 {
221  unsigned Dims[2];
222 
223  Dims[0] = n;
224  Dims[1] = m;
225  return mallocNd(2,Dims,sizeofelt);
226 }
char * BuildIndirectionTable(unsigned nDim, Dims, char ***nextFreeTable, char **nextFreeArray, unsigned sizeofelt)
Definition: mallocNd.c:184
char * malloc_2d(int n, int m, int sizeofelt)
Definition: mallocNd.c:218
char * mallocNd(unsigned int nDim, Dims, unsigned int sizeofelt)
Definition: mallocNd.c:125