3d array

Here is the initialization for 3d array, i.e. n*n*5, the last dimension is 5, n could be any integer.
1
2
3
4
5
6
typedef double vector5 [5];

double (**a)[5] = new  vector5 *[n];

for (int i = 0 ; i < n ; i ++)
  a[i] = new double [n][5];


My question is if I don't use typedef, how could I define the array? And what is the general way to define high-dimensional array with some fixed dimension size?
Last edited on
http://www.cplusplus.com/articles/NAUq5Di1/

However, how about encapsulating everything into a class that might use 1D array to store all data and simply provides an interface that mimics 3D?
cary333 wrote:
if I don't use typedef, how could I define the array?

That's a minor edge case of the C++ grammar: new-expression for a dynamic array of any type that includes parentheses (function pointer, array pointer, etc) cannot be written without a type alias (typedef/using). new (double(*)[5]);, for a single heap-allocated array pointer, is valid, but you can't add [n] anywhere without a syntax error.

As of C++11, you can do a stupidly verbose trick with decltype:
double (**a)[5] = new decltype((double(*)[5])0)[n];
or with the type traits
double (**a)[5] = new std::add_pointer_t<double[5]>[n];
but it's not worth it.

Since C++ has been evolving to avoid explicit calls to new, it's unlikely to change. Use vectors/unique_ptr/third-party/own md array classes. (also note that your data structure is not actually a 3D array: it's a 1D array of pointers to n separately allocated 2D arrays. keskiverto is right in suggesting a class with a single backing array)
Last edited on
You want a 3D vector, just declare one without typedefs and new.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <vector>

int main()
{
   std::cout << "Creating a 3-dimensional vector, enter depth size: ";
   int depth;
   std::cin >> depth;

   std::cout << "Enter row size: ";
   int row;
   std::cin >> row;

   std::cout << "Enter column size: ";
   int col;
   std::cin >> col;

   std::cout << "\n";

   // create a 3 dimensional int vector with known dimensions (initialized to zero)
   using std::vector;
   vector<vector<vector<int>>> aVector(depth, vector<vector<int>>(row, vector<int>(col, 0)));
}

Giving the 3D vector some values is easy with for loops and operator[]:
22
23
24
25
26
27
28
29
30
31
32
33
34
   // initialize the vector with some values
   for (int depth_loop = 0; depth_loop < depth; depth_loop++)
   {
      for (int row_loop = 0; row_loop < row; row_loop++)
      {
         for (int col_loop = 0; col_loop < col; col_loop++)
         {
            aVector[depth_loop][row_loop][col_loop] = (((depth_loop + 1) * 100)
                                                       + ((row_loop + 1) * 10)
                                                       + col_loop + 1);
         }
      }
   }

Instead of using a lot of for loops for output a couple of templated std::ostream overload functions makes for easy display of a 3D vector.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
   for (auto const& x : v)
   {
      os << x << ' ';
   }

   return os;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<std::vector<T>>& v)
{
   for (auto const& x : v)
   {
      os << x << '\n';
   }

   return os;
}

Now displaying a 2D or 3D vector is as easy as
1
2
   // let's display the filled 3D vector
   std::cout << aVector << '\n';


The full code all together:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <vector>

template <typename T>
std::ostream& operator<<(std::ostream&, const std::vector<T>&);
template <typename T>
std::ostream& operator<<(std::ostream&, const std::vector<std::vector<T>>&);

int main()
{
   std::cout << "Creating a 3-dimensional vector, enter depth size: ";
   int depth;
   std::cin >> depth;

   std::cout << "Enter row size: ";
   int row;
   std::cin >> row;

   std::cout << "Enter column size: ";
   int col;
   std::cin >> col;

   std::cout << "\n";

   // create a 3 dimensional int vector with known dimensions
   using std::vector;
   vector<vector<vector<int>>> aVector(depth, vector<vector<int>>(row, vector<int>(col, 0)));

   // let's display the initial 3D vector
   std::cout << aVector << '\n';

   // initialize the vector with some values
   for (int depth_loop = 0; depth_loop < depth; depth_loop++)
   {
      for (int row_loop = 0; row_loop < row; row_loop++)
      {
         for (int col_loop = 0; col_loop < col; col_loop++)
         {
            aVector[depth_loop][row_loop][col_loop] = (((depth_loop + 1) * 100)
                                                       + ((row_loop + 1) * 10)
                                                       + col_loop + 1);
         }
      }
   }

   // let's display the filled 3D vector
   std::cout << aVector << '\n';
}


template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
   for (auto const& x : v)
   {
      os << x << ' ';
   }

   return os;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<std::vector<T>>& v)
{
   for (auto const& x : v)
   {
      os << x << '\n';
   }

   return os;
}

2D and 3D vectors are easier to work with when the dimensions are known at creation time.
However, how about encapsulating everything into a class that might use 1D array to store all data and simply provides an interface that mimics 3D?


this is nice for 2d; for 3d and up its almost required if you want to keep your sanity. You don't have to, but it makes so many things much easier (single linear loop copy / read -write to file etc, and many other operations can be trivialized).


C memory is in simple block format.
1d: c1 c2 c3

2d: r1c1 r1c2 r1c3 r2c1 r2c2 …

3d: z1r1c1 z1r1c2... z1rncn z2r1c1 and so on.

where this breaks down is if you need to grow the thing mid-processing. Its hard to add more rows here: you have to make a new one and copy over with adjusted dimension conversion. triple vector can grow cleanly, but it is a big mess to do most anything else. Got to decide if growing is what you need most, or if fast processing is what you need most.

watch for page fault problems if the structure gets large. you want to iterate across it sequentially, not, for example, hopping around in the z dimension above, that could cause a page fault every single access if it were very large!

Last edited on
> And what is the general way to define high-dimensional array with some fixed dimension size?

This is popular: boost::multi_array<>
https://www.boost.org/doc/libs/1_70_0/libs/multi_array/doc/user.html

Flexible, efficient, and basic usage is quite straightforward. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <boost/multi_array.hpp>
#include <array>
#include <iomanip>

int main()
{
    // an array of 3 dimensions
    using array_3d = boost::multi_array< double, 3 > ;

    const std::size_t m = 5 ;

    std::size_t n ;
    std::cout << "n? " ;
    std::cin >> n ;

    // create an n x n x m array
    std::cout << "\ncreating a " << n << " x " << n << " x " << m << " array\n\n" ;      
    array_3d a( std::array<std::size_t,3> { n, n, m } ) ;

    // fill the array with values
    double v = 0 ;
    for( std::size_t i = 0 ; i < n ; ++i )
        for( std::size_t j = 0 ; j < n ; ++j )
            for( std::size_t k = 0 ; k < m ; ++k )
                a[i][j][k] = v += 0.5 ;
    
    // print it out
    std::cout << std::fixed << std::setprecision(1) ;

    for( const auto& sub_array : a )
    {
        for( const auto& row : sub_array )
        {
            for( double v : row ) std::cout << std::setw(7) << v ;
            std::cout << '\n' ;
        }

        std::cout << "\n\n" ;
    }
}

http://coliru.stacked-crooked.com/a/009ca942425aab2a
Thanks all. Your replies help a lot. I am used to vector as my multi-dimension data structure. But that code which is a part of a big project, is written by someone else. @Cubbi, your explanation is good. Thanks again.
Topic archived. No new replies allowed.