• C

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
LVL 1
YamSengAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
dimitryConnect With a Mentor Commented:
The simplest way to solve this problem is to allocate one dimentinal array and use proper offset:

GLubyte * array;

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

And if you want to access array[i][j][k] you need to
access: array[(i*256+j)*512+k]

0
 
marcjbCommented:
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");
    }
}





0
 
cincin77Commented:
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
0
What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

 
pellepCommented:
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));
  }
}
0
 
pellepCommented:
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));
 }
}
0
 
ecwCommented:
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.

0
 
tapasmondalCommented:

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.
0
 
kotanCommented:
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);
  }
}
0
 
tapasmondalCommented:
kotan,

I have written the same thing what you have wirtten


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

stars that i state should be after the GLubyte.

sorry for that
0
 
YamSengAuthor Commented:
wow...give me a sec to check it out.  It's just 1 day and there's so much response!

Thanks
0
 
YamSengAuthor Commented:
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?
0
 
BlackDiamondCommented:
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));
  }
}


0
 
ecwCommented:
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.
0
 
tapasmondalCommented:
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));
  }
}



0
 
BlackDiamondCommented:
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.
0
 
YamSengAuthor Commented:
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.
0
 
YamSengAuthor Commented:
BlackDiamond,

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

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));
  }
}

0
 
YamSengAuthor Commented:
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
0
 
ecwCommented:
of course it did, it should've been
  array = malloc(sizeof(*array));

0
 
YamSengAuthor Commented:
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.
0
 
elfieCommented:
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.


0
 
YamSengAuthor Commented:
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....
0
 
elfieCommented:
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.
0
 
ecwCommented:
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
0
 
YamSengAuthor Commented:
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.
0
 
elfieCommented:
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++.


0
 
YamSengAuthor Commented:
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.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.