Link to home
Start Free TrialLog in
Avatar of YamSeng
YamSeng

asked on

3D array. How to malloc

I have an array which is 3d.  I used to initialise it by just
GLubyte array[256][512][3];

It's for storing pixel colors in gtk.  If I want to malloc the size because it may be variable, how can I do it?

I tried this, but it didn't work.

GLubyte *** array;

array = malloc(sizeof(GLubyte) * 256);

for(i = 0; i < 256; i++)
{
   array[i] = malloc(sizeof(GLubyte) * 512)
   for(j = 0; j < 512; j++)
   {
      array[i][j] = malloc(sizeof(GLubyte) * 3);
   }
}
somehow when I tried accessing it, halfway, it'll have segmentation fault or something.

But if I initialise it with
GLubyte array[256][512][3];
 no problems.

Any ideas?
Yam
Avatar of marcjb
marcjb
Flag of United States of America image

If you have a newer compiler, the C99 Standard supports variable length arrays.  As a result, you can use variables in array declarations.  Here is an example.  Hope it helps,

Marc

#include <stdio.h>

void func(int i, int j, int k);

int main(void)
{
    func(3,4,5);
    /*
       In this example, there are 3*4*5 = 60 values (0-59)
    */
    return 0;
}

void func(int i, int j, int k)
{
    int array[i][j][k];
    int a, b, c;
    int d = 0;

    for ( a = 0; a < i; a++ )
        for ( b = 0; b < j; b++ )
            for ( c = 0; c < k; c++ )
                array[a][b][c] = d++;

    for ( a = 0; a < i; a++ ) {
        for ( b = 0; b < j; b++ ) {
            for ( c = 0; c < k; c++ )
                printf("%02i ", array[a][b][c]);
            printf(" \n");
        }
        printf("\n");
    }
}





ASKER CERTIFIED SOLUTION
Avatar of dimitry
dimitry

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of cincin77
cincin77

try the following:

GLubyte *** array;

array = malloc(sizeof(* * GLubyte) * 256);

for(i = 0; i < 256; i++)
{
  array[i] = malloc(sizeof(* GLubyte) * 512)
  for(j = 0; j < 512; j++)
  {
     array[i][j] = malloc(sizeof(GLubyte) * 3);
  }
}

Take care of the stars in the first two mallocs!!

regards
or use calloc()

GLubyte *** array;

array = calloc(256, sizeof(GLubyte));

for(i = 0; i < 256; i++)
{
  array[i] = calloc(512, sizeof(GLubyte))
  for(j = 0; j < 512; j++)
  {
     array[i][j] = calloc(3, sizeof(GLubyte));
  }
}
GLubyte *** array;

array = (GLubyte***)calloc(256, sizeof(GLubyte));

for(i = 0; i < 256; i++)
{
 array[i] = (GLubyte**)calloc(512, sizeof(GLubyte))
 for(j = 0; j < 512; j++)
 {
    array[i][j] = (GLubyte*)calloc(3, sizeof(GLubyte));
 }
}
Glubyte (*array)[256][512][3];

*array = malloc(sizeof(*array));

for (i = 0; i < 256; ++i)
  for (j = 0; j < 512; ++j) {
    (*array)[i][j][0] = x;
    (*array)[i][j][1] = y;
    (*array)[i][j][2] = z;
  }

ie. declare array to be a pointer to a 256*512*3 array of chars.


Suppose int array[256][512][3];

 

array=(int ***)malloc(256 * sizeof(int **));
 for(i=0;i<256;i++)
 {
   array[i]=(int **)malloc(512 * sizeof(int*));
   for(j=0;j<512;j++)
   {
      array[i][j]=(int *)malloc(3 * sizeof(int));
   }
 }

 c=(double **)malloc(n * sizeof(double *));
 for(i=0;i<n;i++)
   c[i]=(double *)malloc(n * sizeof(double));


I think it will work perfectly.
Try this,

GLubyte ***array;

array =(GLubyte***) malloc(sizeof(GLubyte **) * 256);

for(i = 0; i < 256; i++)
{
  array[i] = (GLubyte**)malloc(sizeof(GLubyte *) * 512)
  for(j = 0; j < 512; j++)
  {
     array[i][j] = (GLubyte*) malloc(sizeof(GLubyte) * 3);
  }
}
kotan,

I have written the same thing what you have wirtten


tapas
oh! Sorry!
The points should be yours. :-)
For my comment;

stars that i state should be after the GLubyte.

sorry for that
Avatar of YamSeng

ASKER

wow...give me a sec to check it out.  It's just 1 day and there's so much response!

Thanks
Avatar of YamSeng

ASKER

right....I've some results.

I realise that having an array[x][y][z] is different to having an ***array and malloc-ing it.

Maybe the structure of the array is different.

What exactly happened was that if I have 2 arrays

int array[x][y][x];

and

int ***array2;  which later uses malloc accordingly.

But the interesting part is that

array[1][1][1] and array2[1][1][1] can have the same value.  But if a function were to use the arrays created sequentially, I think the intialised array will not work.  Only the malloc-ed array will work.

In the function I use (infact it's some OpenGl library; gtkgl), that function don't access the array sequentially.

So, my question is...is there a way to malloc it, or dynamically define the array such that it is exacly the same as a initialised normal array?
Tapas, you were very close.  The problem with the mallocs here is that only the last pointer is pointing to an actual "GLubyte".  The first 2 pointers are simply pointing to another pointer of size int (actually unsigned, but is the same size).  So the malloc should look like the following.


GLubyte *** array;

array=(GLubyte ***)malloc(256 * sizeof(int));
for(i=0;i<256;i++)
{
  array[i]=(GLubyte **)malloc(512 * sizeof(int));
  for(j=0;j<512;j++)
  {
     array[i][j]=(GLubyte *)malloc(3 * sizeof(GLubyte));
  }
}


YamSeng, see my comment above.  I take it you do not want an array of pointers, just a 393216 GLubyte size block of memory treated as a 3-dim array.  If so, use the syntatic sugar I mentioned previously which is neccessary because in 'C' [] has higher precedence than pointer dereference.
Black :: I think u are wrong.
Bcos u have to pointing other address.
so u have to assign like as:

array=(int ***)malloc(256 * sizeof(int **));


YAMSENG:: U just apply my comment, i think it will work that u want.

array=(int ***)malloc(256 * sizeof(int **));
for(i=0;i<256;i++)
{
  array[i]=(int **)malloc(512 * sizeof(int*));
  for(j=0;j<512;j++)
  {
     array[i][j]=(int *)malloc(3 * sizeof(int));
  }
}



Tapas,
I am very right.  Tell me, what is the size of an "int **" ?  Is it not simply a pointer?  That pointer will consume 32 bits (assuming a 32 bit machine).  Therefor:

sizeof(int **********) = sizeof(int *) = sizeof(int) = 32 bits (4 bytes) any way you slice it!

Try printing it out.  See what you get. (grumble)

Also, the last allocation "array[i][j]=(int *)malloc(3 * sizeof(int));" that you are trying to show is incorrect.  He is looking for an array of GLubytes, not an array of integers.  Please show some proof that I am wrong, because I have done this type of allocation thousands of times, and am confident in my answer.
Avatar of YamSeng

ASKER

tapas, I've tried your code as well as all other codes as well.....none of them worked.

ecw, yours had compilation problem.  I'll post the errors later when I get back home.
Avatar of YamSeng

ASKER

BlackDiamond,

I'll try your codes tonight. Till then, thanks.

YAMSENG::
I have tried this code in VC++. It works fine. but u did not get any result? how it is possible?

int array[256][512][3];



array=(int ***)malloc(256 * sizeof(int **));
for(i=0;i<256;i++)
{
  array[i]=(int **)malloc(512 * sizeof(int*));
  for(j=0;j<512;j++)
  {
     array[i][j]=(int *)malloc(3 * sizeof(int));
  }
}

Avatar of YamSeng

ASKER

Visual C?  Oh...Then I'm not sure....Coz I'm actually using doing opengl using gtkgl. And it's on a Linux platform...

or maybe it works for int but not GLubytes?  8) I have no idea.....

Yam
of course it did, it should've been
  array = malloc(sizeof(*array));

Avatar of YamSeng

ASKER

BlackDiamond, your code didn't work as well....

ecw, your malloc code works BUT it doesn't allow me to make the size of the array variable.  So I can't use it either.

I think what happens is that, the structure of a 3D array and a malloc-ed 3D array doesn't seems to be the same structually.  I strongly believe this could be the reason why it's failing me when I pass it to a function in gtlgl.

I'll post more info when I've finished testing the differences in the structure of the arrays.
Some remarks.
If you define arrays "int array[10][15]", then a memory block of 150 consecutive 'int's is allocated. (in total -if 32 bit machine- you have 600 bytes)

If you define int ** array and do mallocs to 'simulate the [10][15] structure', it means you have a double reference to the 'values'. Array is a pointer (4bytes) pointing to an array of 10 pointers (40 bytes). Eahc of these 10 pointers point to an array of 15 int's. These last 15 arrays are not necessary 'consecutive' place in memory. It's likely that are some gaps. In total teh **array solution takes 644 bytes in memory. Thus abviously not the same 'layout' as array[10][15].

To make it more clear to print out all value of array[10][15], one can use the following
int *i;
int array[10][15];
// initialize array
i=&array[0][0];
for(j=0;j<512;j++)
  print ("%d:%d\n",j,i[j]);

Please always bare in mind that although you can do 'about' the same with arrays as with pointers, they behave different, and have 'internally in memory' different layouts.


Avatar of YamSeng

ASKER

Hmm....that's what I've just found out now. 8)  Maybe it's because of the pointers...and there's gaps when I printed them out sequentially.

So, I'm thinking maybe I have to malloc the total size of it, at once....and use them sequential....but I'll have to verify them later....
calculate the total, and have the 3d array simulated by 3 for loops.
This way you have the dynamic solution, AND the consecutive 'memory' layout.
No you made no mention of dynamically sizing the the array dimensions, if that's what you want, you have to use the method elfie described.  The structure of a 3D array and a malloced 3D array are identical, just one contiguous block of memory.  The difference is in how you access it.  I've seen too many people assume that arrays and pointers are interchangable, and use code similar to,

(in file 1)
  int data[100];

(and in file 2)
  extern int *data;

And then wonder why the code crashes
Avatar of YamSeng

ASKER

Malloc-ing a 3D array using "for loops" and using pointer to pointers to pointers will have gaps between these mallocs.  So it's never contiguous.  I've done a simple 3D array using malloc for each x,y,z and have realised that they are not contiguous.

ecw, I did mention in my question, that the size needs to be variable.

Someone mentioned about using a 1D array and proper offset.  Now I think this could be the only way so as to make it compatible.  But when I was trying his code, I think the offsets were slightly off or something like that.  Nonetheless, I'll give it a shot again tonight.

Later.
what i ment with malloc the 3 for loops is as follows (only 1 malloc, and use calculations to simulate the 3d)

something like
int max_i, max_j, max_k;
char *array;
char *c;

array = malloc (max_i*max_j*max_k);

for(i=0;i<max_i;i++)
 for(j=0;j<max_j;j++)
  for(k=0;j<max_j;k++)
   for(i=0;i<max_i;i++)
    array [i*max_k*max_j+j*max_x+k] = init_value;
With this method you can access the array like a 3D array.
If you want make a define of it

#define get_array_el(i,j,k) array[i*max_k*max_j+j*max_x+k]

thsi way the code can look like
for(i=0;i<max_i;i++)
 for(j=0;j<max_j;j++)
  for(k=0;j<max_j;k++)
     get_array_el(i,j,k) = init_value;

Defined like this the array can be scanned by 1 loop as can be done for 'real'array.
c=&array[0];
and use c as a pointer to elements. To reach the next element use c++.


Avatar of YamSeng

ASKER

you were the first to suggest using a 1D array.  But the offset you gave me were wrong.  

anyway, I'm using array[counter++] and it's easier.