Rog Matthews
Rog Matthews

Reputation: 3247

Assign Memory to 3D array using triple pointer

I have to assign memory to a 3D array using a triple pointer.

#include <stdio.h>
int main()
{
    int m=10,n=20,p=30;
    char ***z;
    z = (char***) malloc(sizeof(char**)*m*n*p);
    return 0;
}

Is this correct way of doing this?(I think what i am doing is incorrect.)

Upvotes: 5

Views: 11202

Answers (5)

John Bode
John Bode

Reputation: 123458

If you don't need the memory to be allocated in a single, contiguous chunk (which IME is the usual case), you would do something like this:

char ***z;
z = malloc(sizeof *z * m); // allocate m elements of char **
if (z)
{
  int i;
  for (i = 0; i < m; i++)
  {
    z[i] = malloc(sizeof *z[i] * n); // for each z[i], 
    if (z[i])                        // allocate n elements char *
    {
      int j;
      for (j = 0; j < n;j++)
      {
        z[i][j] = malloc(sizeof *z[i][j] * p); // for each z[i][j], 
        if (z[i][j])                           // allocate p elements of char
        {
           // initialize each of z[i][j][k]
        }
      }
    }
  }
}

Note that you will need to free this memory in reverse order:

for (i = 0; i < m; i++)
{
  for (j = 0; j < n; j++)
    free(z[i][j];
  free(z[i]);
}
free(z);

If you really need the memory to be allocated in a contiguous chunk, you have a couple of choices. You could allocate a single block and compute your offsets manually:

char *z = malloc(sizeof *z * m * n * p); // note type of z!
...
z[i * m + j * n + k] = some_value();

When you're done, you just need to do a single free:

free(z);

If you have a C99 compiler or a C11 compiler that supports variable-length arrays, you could do something like this:

int m=..., n=..., p=...;
char (*z)[n][p] = malloc(sizeof *z * m);

This declares z as a pointer to an nxp array of char, and we allocate m such elements. The memory is allocated contiguously and you can use normal 3-d array indexing syntax (z[i][j][k]). Like the above method, you only need a single free call:

free(z);

If you don't have a C99 compiler or a C11 compiler that supports VLAs, you would need to make n, and p compile-time constants, such as

#define n 20
#define p 30

otherwise that last method won't work.

Edit

m doesn't need to be a compile-time constant in this case, just n and p.

Upvotes: 2

Jon Cage
Jon Cage

Reputation: 37448

You want sizeof(char) not sizeof(char**) as the latter will give you the size of a pointer which on most modern systems will be 4 bytes instead of the 1 you're expecting.

Upvotes: 0

unwind
unwind

Reputation: 399703

There's no need to cast the return value of malloc(), in C.

And if you expect to store m * n * p characters directly (and compute the address yourself), then you should of course not scale the allocation by the size of a char **.

You mean:

int m = 10, n = 20, p = 30;
char *z = malloc(m * n * p * sizeof *z);

This will allocate 10 * 20 * 30 = 6000 bytes. This can be viewed as forming a cube of height p, with each "slice" along the vertical axis being n * m bytes.

Since this is for manual addressing, you cannot use e.g. z[k][j][i] to index, instead you must use z[k * n * m + j * m + i].

Upvotes: 4

Superman
Superman

Reputation: 3083

You would need the following nested loop -

z = (char**)malloc(sizeof(char*) * m);
for (int i = 0; i < m; ++i)
{
    *(z + i) = (char*)malloc(sizeof(char*) * n);
    for (int j = 0; j < n; ++j)
    {
        *(*(z + i)) = (char)malloc(p);
    }
}

May not be synactically accurate, but it should be something along these lines.

Upvotes: 0

Paul R
Paul R

Reputation: 212929

To completely allocate a 3D dynamic array you need to do something like the following:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int m=10,n=20,p=30;
    char ***z;

    z = malloc(m * sizeof(char **));
    assert(z != NULL);
    for (i = 0; i < m; ++i)
    {
        z[i] = malloc(n * sizeof(char *));
        assert(z[i] != NULL);
        for (j = 0; j < n; ++j)
        {
            z[i][j] = malloc(p);
            assert(z[i][j] != NULL);
        }
    }
    return 0;
}

Freeing the data is left as an exercise for the reader.

Upvotes: 6

Related Questions