Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Declaring 3d array using new/typedef.

Credits go to Oscar Giner and William Labbett for helping out!
This thread is locked; no one can reply to it. rss feed Print
 1   2 
Declaring 3d array using new/typedef.
verthex
Member #11,340
September 2009
avatar

Cookies to whoever solves this one. I found the following code on this page and I'm wondering how to modify it to 3d? I also don't get the typedef part since I never use typedefs.

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

int main(int argc, char **argv) {

typedef double (array5k_t)[5000];

array5k_t *array5k = new array5k_t[5000];

array5k[4999][4999] = 10;
printf("array5k[4999][4999] == %f\n", array5k[4999][4999]);

return 0;
}

edit: Oh and how do I delete the whole thing.

William Labbett
Member #4,486
March 2004
avatar

A guess :-

array5k_t **array5k = new (array5k_t *)[5000];

int i;

for(i = 0; i < 5000; ++i)
{
   array5k[i] = new (array5k_t)[5000];
}

verthex
Member #11,340
September 2009
avatar

I tried this:

#SelectExpand
1#include <stdio.h> 2#include <stdlib.h> 3 4int main(int argc, char **argv) 5{ 6 7 typedef double (array5k_t)[5000]; 8 9 array5k_t **array5k = new (array5k_t*)[5000]; 10 11 for(i = 0; i < 5000; ++i) 12 { 13 array5k[i] = new (array5k_t)[5000]; 14 } 15 16 array5k[0][0][0] = 0; 17 18 std::cout<<array5k[0][0][0]<<std::endl; 19 20return 0; 21}

These were the errors

In function 'int main(int, char**)':|
|9|error: array bound forbidden after parenthesized type-id|
|9|note: try removing the parentheses around the type-id|
|11|error: 'i' was not declared in this scope|
|13|error: array bound forbidden after parenthesized type-id|
|13|note: try removing the parentheses around the type-id|
|18|error: 'cout' is not a member of 'std'|
|18|error: 'endl' is not a member of 'std'|
||=== Build finished: 5 errors, 0 warnings ===|

I also tried this

#SelectExpand
1#include <stdio.h> 2#include <stdlib.h> 3 4int main(int argc, char **argv) 5{ 6 7 typedef double (array5k_t)[5000]; 8 9 array5k_t **array5k = new array5k_t *[5000]; 10 11 for(int i = 0; i < 5000; ++i) 12 { 13 array5k[i] = new (array5k_t)[5000]; 14 } 15 16 array5k[0][0][0] = 0; 17 18 std::cout<<array5k[0][0][0]<<std::endl; 19 20return 0; 21}

William Labbett
Member #4,486
March 2004
avatar

#SelectExpand
1#include <stdio.h> 2#include <stdlib.h> 3#include <iostream> 4 5using namespace std; 6 7 8int main(int argc, char **argv) 9{ 10 int i; // must declare i to use it later 11 12 typedef double array5k_t[5000]; 13 14 array5k_t **array5k = new array5k_t *[5000]; 15 16 for(i = 0; i < 5000; ++i) 17 { 18 array5k[i] = new array5k_t [5000]; 19 } 20 21 array5k[0][0][0] = 1000; 22 23 std::cout<<array5k[0][0][0]<<std::endl; 24 25 return 0; 26}

That any better ?

I thought the brackets in the typedef were wrong.

There might something wrong with the lines which use 'new' here I think.

//editted

Oscar Giner
Member #2,207
April 2002
avatar

I'd just get rid of that typedef and do it the normal way:

#SelectExpand
1double ***array3d; 2array3d = new double**[5000]; 3 4for(i=0; i<5000; ++i) 5{ 6 array3d[i] = new double*[5000]; 7 for(j=0; j<5000; ++j) 8 { 9 array3d[i][j] = new double[5000]; 10 } 11} 12 13array3d[4999][4999][4999] = 10; 14printf("array3d[4999][4999][4999] == %f\n", array3d[4999][4999][4999]); 15 16for(i=0; i<5000; ++i) 17{ 18 for(j=0; j<5000; ++j) 19 { 20 delete[] array3d[i][j]; 21 } 22 delete[] array3d[i]; 23} 24delete[] array3d;

verthex
Member #11,340
September 2009
avatar

@William:
How do you delete it?

@Oscar.

Thanks, I know that already but I wanted to get sophisticated with the typedef usage.

suggestions, unless you have 5000^3 double in ram use this instead:

#SelectExpand
1#include <stdio.h> 2#include <stdlib.h> 3#include <iostream> 4 5using namespace std; 6 7 8int main(int argc, char **argv) 9{ 10 int i; // must declare i to use it later 11 12 typedef double array5k_t[50]; 13 14 array5k_t **array5k = new array5k_t *[50]; 15 16 for(i = 0; i < 50; ++i) 17 { 18 array5k[i] = new array5k_t [50]; 19 } 20 21 array5k[0][0][0] = 1000; 22 23 std::cout<<array5k[0][0][0]<<std::endl; 24 25 return 0; 26}

anonymous
Member #8025
November 2006

The point is that you allocate an array of arrays all at once. It doesn't matter how many dimensions the array has.

#include <stdio.h>
#include <stdlib.h>
 
int main() {
 
  typedef double array10_10_t[10][10];
 
  array10_10_t *arr = new array10_10_t[20];
 
  arr[15][2][0] = 10;
  printf("arr[15][2][0] == %f\n", arr[15][2][0]);
  delete[] arr;
  return 0;
}

William Labbett
Member #4,486
March 2004
avatar

#SelectExpand
1#include <stdio.h> 2#include <stdlib.h> 3#include <iostream> 4 5using namespace std; 6 7 8int main(int argc, char **argv) 9{ 10 int i; // must declare i to use it later 11 12 typedef double array5k_t[50]; 13 14 array5k_t **array5k = new array5k_t *[50]; 15 16 for(i = 0; i < 50; ++i) 17 { 18 array5k[i] = new array5k_t [50]; 19 } 20 21 array5k[0][0][0] = 1000; 22 23 std::cout<<array5k[0][0][0]<<std::endl; 24 25 for(i = 0; i < 50; ++i) 26 { 27 delete[] array5k[i]; 28 } 29 30 delete[] array5k; 31 32 return 0; 33}

You could also use something like

typedef double (*ptr_to_array)[50];
typedef double *ptr_to_array 3d_array;

3d_array actual_array;

for(i = 0; i < 50; ++i)
{
   for(j = 0; j < 50; ++j)
   actual_array[j][i] = new double [50];

}

Probaably doesn't work, but there's room for improvement on that code.

/* EDIT */

no definitely doesn't work.

actual_array need to be allocated some memory too.

/* EDIT 2 */

Sorry. I aught to test it first.

verthex
Member #11,340
September 2009
avatar

anonymous said:

The point is that you allocate an array of arrays all at once. It doesn't matter how many dimensions the array has.

So that it looks more compact than Oscars way? Or it takes a few lines less code?

Oscar Giner
Member #2,207
April 2002
avatar

It's different, in the sense that the "typedefed" array must have a constant size.

Accessing it should be faster, since it should have one less indirection (in case of 2d: instead of creating an array of pointers each one pointing to a row, you create a big table in memory with all data contiguous so accessing it is similar to a static 2d array).

OnlineCop
Member #7,919
October 2006
avatar

Would it not be simpler (both in complexity and in understanding what is doing what) if you just used a struct?

typedef struct 3d{
   double x,y,z;
} 3d;

I don't see in what way you'll ever be using a 3D array like what you're suggesting: Every single point (5000*5000*5000) will have a single double in it: not a 3D coordinate; just a single floating-point value.

This won't really be useful to you. If you're trying to conceptualize something in 3-space, and you have 5000 points scattered around that space, you want 5000*3 to mark each particle's coordinates.

What you WANT is a coordinate for each particle (be it a point, a polygon, or even a sprite), and you can get 5000 of those easily (particle pumps).

--
You: Yeah! I'm gonna get stuff done today!
Internet: Nope! *POW*

verthex
Member #11,340
September 2009
avatar

OnlineCop said:

I don't see in what way you'll ever be using a 3D array like what you're suggesting: Every single point (5000*5000*5000) will have a single double in it: not a 3D coordinate; just a single floating-point value.

Oh the example he gave on the link I used had 5000. I just need something like 5 really. It could be used for Ising modelling, maybe thats what he needed it for or the dimer problem.

Accessing it should be faster,

Accessing your code or the typedef code?

Edgar Reynaldo
Member #8,592
May 2007
avatar

Use a simple class, a one dimensional array, and an accessor function to take care of finding the right index for a given z,y,x triplet.

#SelectExpand
1class ThreeDArray { 2private : 3 int d;// depth 4 int h;// height 5 int w;// width 6 double* array; 7public : 8 ThreeDArray() : d(0) , h(0) , w(0) , array(0) {} 9 ~ThreeDArray() {Free();} 10 void Resize(int depth , int width , int height) { 11 Free(); 12 array = new double[depth*width*height]; 13 } 14 15 double& Get(int z , int y , int x) { 16 return array[z*w*h + y*w + x]; 17 } 18};

C/C++ Reference -|- cplusplus.com - The C++ Resources Network -|- SGI's STL guide
Proverbs 15:33 The reverence of the LORD is the instruction of wisdom; And before honour is humility.
My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense)

verthex
Member #11,340
September 2009
avatar

Its nice Edgar, been looking for one of those except I always wondered if hashing the coordinates using multiplication takes longer than just using a standard access of?

int array[depth][width][height];

Edgar Reynaldo
Member #8,592
May 2007
avatar

Well, it's {3 MULT, 2 ADD, 1 ACCESS} vs. {3 ACCESS}. The second way is probably somewhat faster, but then you have to deal with dereferencing three arrays, and they aren't stored sequentially like the first version would be. You'd have to profile it to see.

C/C++ Reference -|- cplusplus.com - The C++ Resources Network -|- SGI's STL guide
Proverbs 15:33 The reverence of the LORD is the instruction of wisdom; And before honour is humility.
My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense)

verthex
Member #11,340
September 2009
avatar

but then you have to deal with dereferencing three arrays,

How exactly does c++ create a multidimensional array, what type of data structure is it? If you could give a link that would be fine.

I already know from some testing that accessing a std::vector array is slower than a regular one.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Well, there is a difference between a 3D compile time array, and a 3D run time array that you manually allocate as an array of arrays of arrays. The compile time array will be faster, but it's size has to be determined at compile time.

Google / profile FTW.

C/C++ Reference -|- cplusplus.com - The C++ Resources Network -|- SGI's STL guide
Proverbs 15:33 The reverence of the LORD is the instruction of wisdom; And before honour is humility.
My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense)

verthex
Member #11,340
September 2009
avatar

Google / profile FTW.

??? <-linky

Edgar Reynaldo
Member #8,592
May 2007
avatar

No, I meant 'Google' or 'Profile' For The Win. Not Google 'profile ftw'.

C/C++ Reference -|- cplusplus.com - The C++ Resources Network -|- SGI's STL guide
Proverbs 15:33 The reverence of the LORD is the instruction of wisdom; And before honour is humility.
My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense)

kdevil
Member #1,075
March 2001
avatar

As an alternative, look into boost::multi_array. To create a 3D array of, say, 5000x5000x10, you can do:

#include <boost/multi_array.hpp>

boost::multi_array<int, 3> some_array (boost::extents[5000][5000][10]);

and then assign/retrieve values the way you'd expect:

int values = 0;
for (int i = 0; i < 5000; i++) 
  for (int j = 0; j < 5000; j++)
    for (int k = 0; k < 10; k++)
      some_array[i][j][k] = values++;

int my_value = some_array[1][2][3];

-----
"I am the Black Mage! I casts the spells that makes the peoples fall down!"

verthex
Member #11,340
September 2009
avatar

kdevil said:

As an alternative, look into boost::multi_array.

For some reason I'm tempted to ask if its better than std::vector?

kdevil
Member #1,075
March 2001
avatar

Neither is really "better": boost::multi_array and std::vector are designed to solve different problems (easy multidimensional arrays, and easy re-sizable arrays).

If you're asking which is faster, I haven't done any tests, but I imagine they're probably both about the same.

Edit: Scratch that. They might be the same for a 1D array, but I'm positive that a 3-dimensional multi_array will be significantly faster than its vector equivalent (a vector of vectors of vectors).

-----
"I am the Black Mage! I casts the spells that makes the peoples fall down!"

verthex
Member #11,340
September 2009
avatar

I dissassembled the following code in codeblocks with GDB 7.2:

int main()
{
  int array[10];

  //array[1] = 0;

  //int value = array[1];

  //return 0;
}

00401318  push   %ebp
00401319  mov    %esp,%ebp
0040131B  and    $0xfffffff0,%esp
0040131E  sub    $0x30,%esp
00401321  call   0x401720 <__main>
00401326  mov    $0x0,%eax
0040132B  leave
0040132C  ret

Does the line:

 call   0x401720 <__main>

relate to,

int main()

or the exit of main?

Notice I have no return and yet it has it.

Is this the way its looked up BTW?

array[z*w*h + y*w + x];

like Edgar had it?

OnlineCop
Member #7,919
October 2006
avatar

__main is name-mangled (munged) and there is actually another entry point. This basically calls the "real" main() function after allocating 0x30 bytes (48 bytes) on the stack.

Since you declared main() to return an int, but neglected to include it, the compiler in this case returned 0. That functionality can vary by compiler.

--
You: Yeah! I'm gonna get stuff done today!
Internet: Nope! *POW*

Arthur Kalliokoski
Member #5,540
February 2005
avatar

OnlineCop said:

That functionality can vary by compiler.

I thought C++ was supposed to do that by design.

I really admire the U.S. Constitution. It's so much better than what we have now.

 1   2 


Go to: