return a pointer to a multidimensional array

Hi, in working with multidimensional arrays, how do I return a pointer to such an array without using some type of type cast before/after the call?

I hope the following code clearly explains my question. I do not know the proper syntax for the return argument on the returnPointer function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// initialize reference array
int referenceMat[][7] = {{1,2,3,4,5,6,7},{1,2,3,4,5,6,7}};

// return a pointer to the reference array preserving the row length
int(*)[7] returnPointer(void) // <--- WHAT SYNTAX DO I USE HERE TO MAKE THIS WORK?
{
  return referenceMat;
}

void main()
{
  int (*mat)[7]; // pointer to an array of row length 7

  // get a pointer to the reference array (this works)
  mat = referenceMat;

  // get a pointer to the reference array (I want this syntax to behave
  // just like the previous line without any typecasts)
  mat = returnPointer();

  // do something with the array
  printf("%d\n", mat[0][2]);

}


Thanks!
Last edited on
multidimensional arrays


I really should get around to writing that article about why multidimensional arrays are so evil.

Anyway... the easiest way is to typedef it, as this removes as much as the multidimentional array-ness of the syntax as possible whilst still keeping it a multidimentional array:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef int int7[7];

int7 referenceMat[] = {{1,2,3,4,5,6,7},{1,2,3,4,5,6,7}};

int7* returnPointer()
{
  return referenceMat;
}

int main()  // int main!  not void!
{
  int7* mat;

  mat = returnPointer();

  return 0;
}


A better way would be to just not use multidimentional arrays at all because they lead to endless levels of this kind of syntax and type confusion throughout the program's lifetime.
Anyway... the easiest way is to typedef it,


Thanks Disch,

Is there any way to do this without using a typedef? It would seem odd that one can pass a reference to a multidimensional array as an argument, but not return one.

I'm trying to avoid doing a typedef of the same thing in multiple independent classes, though that's the best solution I have found so far.
Last edited on
Is there any way to do this without using a typedef?


If there is, I don't know about it. I've tried every reasonable permutation of *, int, and [7] I could think of and none of them worked.

that's the best solution I have found so far.


Well like I say... the better solution is just not to use multidimentional arrays at all.

Multidimentional arrays are just syntax sugar (or really, syntax poison) for 1D arrays. Ex:

1
2
3
4
5
6
7
// this...
int two[2][7];
two[1][3] = 0;

// is really the same as this:
int one[2*7];
one[(1*7)+3];


Having to use the '7' constant directly like that isn't ideal, but that's what classes are for!

Write a simple class for 2D arrays and just use objects of that class instead of actual arrays. Rather than using the [] operator to get [x][y], use the parenthesis operator to get (x,y).

Here's a basic template class I whipped up. You can add features as needed:

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
template <typename T>
class Array2D
{
public:
    Array2D(unsigned wd,unsigned ht)
        : nWd(wd), nHt(ht)
        , mBuf(new T[wd*ht])
    { }
    
    ~Array2D()
    {
        delete[] mBuf;
    }
    
    //------------------------
    // info
    unsigned GetWd() const { return nWd;    }
    unsigned GetHt() const { return nHt;    }
    
    //------------------------
    // element access
    T& operator () (unsigned x,unsigned y)
    {
        return mBuf[ (y*nWd) + x ];
    }
    
    const T& operator () (unsigned x,unsigned y) const
    {
        return mBuf[ (y*nWd) + x ];
    }
    
private:
    // data members
    unsigned    nWd;
    unsigned    nHt;
    T*          mBuf;
    
    //--------------------
    // to prevent accidental copying
    Array2D(const Array2D<T>&);
    Array2D<T>& operator = (const Array2D<T>&);
};


Usage would be something like:

1
2
3
Array2D<int> foo(2,7);

foo( x, y ) = 10; // etc 



Alternatively, if you don't want the array dynamically allocated, you could template the dimensions:
1
2
3
4
5
6
7
8
9
10
11
template <typename T, unsigned wd, unsigned ht>
class Array2D
{
    //...
private:
    T mBuf[wd*ht];
};

//---------------------

Array2D<int,2,7> foo;



There *are* ways to have 1-line initializers:

1
2
3
4
5
int foo[2*7] = {1, 2, 3, ...}; // so you can do something like this

// but it would end up looking like this:
Array2D<int> foo(2,7,
                 1, 2, 3, ... );


It's not pretty, but it'd do-able. You can use variable argument list, which is no fun.


Anyway... then passing arrays by reference and whatnot is easy as pie.
Thanks again, Disch, for your explanation. I can see how a 2d array class would better suit the C++ mentality compared to what I'm doing, but the inner C programmer in me just wants to stick with my arrays of int[7]'s since they make the code (in my opinion) a lot nicer to read and visualize and initialize. For this particular application my 2D array is static const.

Anyhow, I appreciate your time. I'll have to think some more about the best way to do this. Cheers.
Well, I have to disagree that arrays make the code nicer to read and visualize.

Use boost::array<> then:

1
2
3
4
boost::array<int, 7> foo = { 1, 2, 3, 4, 5, 6, 7 };

foo[ 3 ] = 4;
std::cout << foo[ 2 ] << std::endl;


What you can't do, however, is:

1
2
3
boost::array< boost::array< int, 7 >, 3 > twod = {
    { 1, 2, 3, 4, 5, 6, 7 }, { 8, 9, 10, 11, 12, 13, 14 }, { 15, 16, 17, 18, 19, 20, 21 } 
};

Is there any way to do this without using a typedef? It would seem odd that one can pass a reference to a multidimensional array as an argument, but not return one.


What is odd about it? This problem has been solved in C++ by the standard template library. If you are constructing and returning objects then there is no problem. Moreover, passing by reference is actually more efficient. You don't have to worry about large array objects being copied. Returning arrays by pointer is extraordinarily dangerous since so many beginners have trouble grasping basic memory management concepts. This question keeps getting asked over and over and over and most beginners end up with programs that crash or leak memory because they don't understand why returning pointers to arrays is so dangerous. Passing an array to a function as an in-out parameter is simpler and safer in most cases and in the case of boost or stl objects, it is more efficient. Also, why reinvent the wheel? Unlike Disch, I like the natural syntax of 2d arrays. I would prefer it over writing calculations into the brackets, personally. That is just my two cents but not everyone has to agree on that.

Anyway, there is an article on this. It doesn't talk about returning 2d arrays but there is no reason to ever return a 2d array in my mind. Even if you write your own 2d array class you wouldn't want to return it by value. It'd be better passed to a function as an in-out param.
http://cplusplus.com/forum/articles/7459/
Also, remember that main returns int but not void.
What is odd about it? This problem has been solved in C++ by the standard template library.


Is the solution you're talking about std::vector? Vectors are nice, I use them in many places, but there's simply no need for the extra overhead if you know the object is always a double[3][3]. For clarity, I'm simply trying to use this structure such that I can type

1
2
double x[3][3];
x[1][2] = 1.;

instead of

1
2
double x[9];
x[1 * 3 + 2] = 1.;

though the two syntaxes should be nearly equivalent from a compiler standpoint, as far as I can tell.

Moreover, passing by reference is actually more efficient.


In my example, I'm not passing anything by value, that's very much what I'm trying to avoid.

Returning arrays by pointer is extraordinarily dangerous since so many beginners have trouble grasping basic memory management concepts


Okay, maybe it's "dangerous" and "immoral" but it's very much legal and in some instances, it's the best solution.

I'm using the typedef solution for now.
What overhead are you talking about with std::vector? One memory allocation and deallocation vs. putting
the array on the stack? If so, that's not much overhead considering the benefits of using a class vs. a raw
pointer.

In my example above, the boost::array<> even eliminates the memory allocation and deallocation and is
therefore identical in every respect, including performance, to your 1D array example.


Another option is to make a struct type that contains an array and return that. the struct has a build int operator= which will allow you to easily copy arrays if they are members of a struct. Then you can return the struct by value. Alternatively you could dynamically allocate and return a struct pointer and then have the caller be responsible for its destruction.

What I was trying to get at earlier is that I don't understand why you need to return a pointer to an array. Whay is so bad about passing the array as an in-out parameter? returning a value is not always the solution for getting a function to produce information for you.

One more comment I have is that the size of an array is irrelevant in terms of deciding whether to use a vector. The vector is a class which has construction and copying semantics built in. It also helps prevent memory leaks. It also provides operator[] making it usable in legacy APIs. In my humble opinion, you could use a vector in any new C++ code where you need an array regardless of the size or whether the size is dynamic. The advantage is that the std::vector provides you additional interfaces that make the management and maintenance of the code much easier. Even in the case of a vector, you still should avoid returning them by value. There isn't any point. Even in that case you'd pass the object as an in-out parameter and have the function fill the container via the reference. The only serious gripe that I have with vector is the inability to do aggregate initialization ( = { 0, 1, 2, etc } and the fact that it always default initializes all elements when in some cases that is a complete waste of time. Finally, there are some algorithms that just won't work with a c-style multi-dimensional array due to the lack of copying semantics. Arrays have no operator= or copy constructor. I hope that some of those ideas are received as constructive. They are meant to help you improve your program.
What overhead are you talking about with std::vector?


My main beef with using the vector for this particular application is that it requires more storage and would involve another degree of indirection which would significantly slow down the problem.

1
2
double F[3][3];
F[0][2]; // <-- one address calculation 


versus

1
2
std::vector<std::vector<double>> F;
F[0][2]; // <-- two address calculations (F[0], then ->[2]) 


In addition, the 2d array vector form may not be allocated contiguously in storage. By this I mean F[0][2] is almost certainly not next to F[1][0]. Right? I'm not exactly sure how vector is doing its memory allocations.

In addition, the vector form requires more memory. For this size array, it requires nearly twice as much memory at a minimum (8 ints + 9 doubles). Now, I realize that in the vast majority of applications, both of these issues are negligible as most applications are not computational in nature. My application is computational in nature. The number of double F[3][3] objects in storage is essentially unlimited (i.e. hundreds of thousands, pushing memory limits). Even increasing the size by adding a few extra int's (vector size and capacity) will have an effect, and the increased cost of two indirections while doing computations will also have an effect. Again, I know in most applications this isn't an issue. However, I routinely run my code for days at a time, so even a 20% increase in speed is a big deal for me.

The other problem with vector is that initialization is not as simple/clear as

 
double F[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};


The second Array2D example by Disch keeps looking better as I reread this thread as one could add in debug checks for bounds, but the accessibility and storage are identical as the standard 2D array case. I would imagine this is equivalent to the boost implementation.

I haven't looked at boost too much, but I don't want to install an external library, even one so well developed and maintained as boost. Again, personal preference.

I hope that some of those ideas are received as constructive.


Yes, they are, thank you. Programming is always a learning experience, no matter what level you're at.
Topic archived. No new replies allowed.