I am having some difficulties in understanding the code below. First I don't understand, is (char***) a cast to a triple pointer to a char? While I am am somewhat familiar with single pointers, these triples are beyond my current understanding and I would like to know, what is the point? The second question is, why have 3 initializations, one for "a", one for a[0], and one for a[0][0]? while I somewhat understand that ***a is a/can be a 3D array, I don't understand how having a block of memory of d1*d2*d3*size at a[0][0] is needed, why not just have it the "d3" so it would be like "depth"? Any clue would be much appreciated...

void ***array3(long d1, long d2, long d3, long size)
{
   char ***a;
   long i,j;

   a = (char ***) my_malloc(d1*sizeof(char *));
   a[0] = (char **) my_malloc(d1*d2*sizeof(char *));
   a[0][0] = (char *) my_malloc(d1*d2*d3*size);
   for (i=1;i<d1;i++) {
      a[i] = a[i-1] + d2;
      a[i][0] = a[i-1][0] + d2*d3*size;
   }
   for (i=0;i<d1;i++)
      for (j=1;j<d2;j++)
	 a[i][j] = a[i][j-1] + d3*size;
   return (void ***) a;
}

where my_malloc is:

void *my_malloc(size_t size)
{
   void *ptr;

   if (ptr = (void *) malloc(size))
      return ptr;
   fprintf(stderr,"Memory allocation failed\n");
   exit(1);
}

Thank you,

Brian

Voids don't return, and a well design program IMO should never use exit(). Why would your functions need all these pointers?

void doesn't return, but void * or in this case void *** does.

A char * * * is a pointer to a pointer to a pointer to char.

Its a bit of an odd construct, I don't recall using triple pointers much.

I would agree that you should avoid exit when possible, but in this case, they wanted the program to halt if allocation failed. That is surely what exit() does. I can't really argue their use in this context, feel free to describe how you might prefer to handle an "I can't allocate enough memory" problem MosaicFuneral.

Ok on to making an attempt to understand the code:

Re-posting code with [code=c] so we get line numbers:

void ***array3(long d1, long d2, long d3, long size)
{
   char ***a;
   long i,j;

   a = (char ***) my_malloc(d1*sizeof(char *));
   a[0] = (char **) my_malloc(d1*d2*sizeof(char *));
   a[0][0] = (char *) my_malloc(d1*d2*d3*size);
   for (i=1;i<d1;i++) {
      a[i] = a[i-1] + d2;
      a[i][0] = a[i-1][0] + d2*d3*size;
   }
   for (i=0;i<d1;i++)
      for (j=1;j<d2;j++)
	 a[i][j] = a[i][j-1] + d3*size;
   return (void ***) a;
}

Line 6 allocates (in a) an array of d1 pointers.

Line 7 allocates (in a[0]) enough space to hold an array of d2 pointers for each of the d1 pointers allocated on line 6.

Line 8 allocated (in a[0][0]) enough space to hold all of the data. There are size bytes for each of the d3 data items in each of the d2 pointers (for each of the d1 pointers).

The for loop (lines 9-12) 'fixes' the pointers in a (all d1 of them) on line 10. Then on line 11, it 'fixes' the first d2 pointer for each of them.

The for loop (lines 13-15) 'fixes' all of the rest of the pointers by offsetting from the pointers fixed on line 11 above.

This algorithm does a pretty good job of minimizing the number of allocations. This is generally a good thing for the memory allocator and it also provides good co-location of the data in memory. (All of the data in the array is 'near' the other data in the array.)

Some remarks about exit() in C:
The exit call considered harmful in C++ but not in C where "a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument" (C Std, 5.1.2.2.3 Program termination) and "The exit function causes normal program termination to occur" (ibid, 7.20.4.3).

This article has been dead for over six months. Start a new discussion instead.