Solved

3D array. How to malloc

Posted on 2002-05-09
30
2,694 Views
Last Modified: 2007-11-27
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
0
Comment
Question by:YamSeng
  • 9
  • 4
  • 4
  • +7
30 Comments
 
LVL 3

Expert Comment

by:marcjb
ID: 6998858
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
 
LVL 11

Accepted Solution

by:
dimitry earned 50 total points
ID: 6998860
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
 
LVL 3

Expert Comment

by:cincin77
ID: 6998998
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
 
LVL 4

Expert Comment

by:pellep
ID: 6999929
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
 
LVL 4

Expert Comment

by:pellep
ID: 6999965
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
 
LVL 5

Expert Comment

by:ecw
ID: 6999991
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
 
LVL 1

Expert Comment

by:tapasmondal
ID: 7000433

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
 
LVL 6

Expert Comment

by:kotan
ID: 7000503
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
 
LVL 1

Expert Comment

by:tapasmondal
ID: 7000674
kotan,

I have written the same thing what you have wirtten


tapas
0
 
LVL 6

Expert Comment

by:kotan
ID: 7000703
oh! Sorry!
The points should be yours. :-)
0
 
LVL 3

Expert Comment

by:cincin77
ID: 7000754
For my comment;

stars that i state should be after the GLubyte.

sorry for that
0
 
LVL 1

Author Comment

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

Thanks
0
 
LVL 1

Author Comment

by:YamSeng
ID: 7006675
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
 
LVL 5

Expert Comment

by:BlackDiamond
ID: 7007162
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
 
LVL 5

Expert Comment

by:ecw
ID: 7007287
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
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 1

Expert Comment

by:tapasmondal
ID: 7007617
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
 
LVL 5

Expert Comment

by:BlackDiamond
ID: 7007811
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
 
LVL 1

Author Comment

by:YamSeng
ID: 7008071
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
 
LVL 1

Author Comment

by:YamSeng
ID: 7008075
BlackDiamond,

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

Expert Comment

by:tapasmondal
ID: 7008200

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
 
LVL 1

Author Comment

by:YamSeng
ID: 7008291
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
 
LVL 5

Expert Comment

by:ecw
ID: 7008703
of course it did, it should've been
  array = malloc(sizeof(*array));

0
 
LVL 1

Author Comment

by:YamSeng
ID: 7010465
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
 
LVL 3

Expert Comment

by:elfie
ID: 7010576
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
 
LVL 1

Author Comment

by:YamSeng
ID: 7010591
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
 
LVL 3

Expert Comment

by:elfie
ID: 7010595
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
 
LVL 5

Expert Comment

by:ecw
ID: 7010615
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
 
LVL 1

Author Comment

by:YamSeng
ID: 7010659
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
 
LVL 3

Expert Comment

by:elfie
ID: 7010715
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
 
LVL 1

Author Comment

by:YamSeng
ID: 7012848
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

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now