Take the 2-minute tour ×

I am using a library that takes a pointer to a double array as an argument, called as follows:

const int N=10;
const int J=20;
double my_array[N*J];
libFunc(my_array, N, J);

I would prefer to work with multidimensional arrays in my code, and I have discovered that I can call libFunc by dereferencing my multidimensional double array as follows

double my_array2[N][J];
libFunc(&my_array2[0][0], N, J);

However, I am worried that this code might not be portable, that it may not continue to work as N and M get large, and that there may be other hidden problems.

Why is this bad, what should I look out for here? What is the proper way to use multidimensional arrays and pass them to libFunc as if they were ordinary double arrays?

Edit: Read the comments below the selected answer for a discussion of the issue at hand. It seems that if I declare a static array, as is done above, then this code should work on most compilers. However if the array is dynamically allocated there may be an issue.

share|improve this question
@FailedDev admittedly it is syntactic sugar. But it significantly clarifies my code when the number of dimensions gets large. E.g., I can write my_array4[i][j][k][1] instead of my_array3[i*J*K*M+j*K*M+k*M+1]. Re the suggestion at the beginning of your post, can you clarify? –  kalu Dec 3 '11 at 22:12
I have been using the following hack inline int idx(const int& x, const int& y, const int& z) {return x*Ny*Nz + y*Nz + z;}. Maybe its bad form, but it works and is transparent. –  kalu Dec 4 '11 at 4:11

3 Answers 3

There is no simple way short of making a copy. Accessing an array outside its bounds is undefined behaviour, and you won't get around this.

Now, it is possible in many situations that your code works, simply because the memory for T[M * N] and for T[M][N] is laid out in the same way. As long as the caller and the callee aren't visible to the compiler at the same time, I would hazard a guess that this should work.

But imagine this scenario:

T a[M][N];

for (size_t i = 0; i != M * N; ++i)
  a[0][i] = 0;

Here the compiler may reason that a[0][N] is out of bounds, and thus there is undefined behaviour, and the compiler may legally omit the entire loop, or make the application crash or wipe your hard disk.

So... take your pick. Undefined behaviour is around somewhere, but you might get lucky.

share|improve this answer
Hm.. Sorry, but I do not understand your point. What are you trying to explain with example? What would be different, if we had T a[NM]* and accessed something beyond its bounds? –  Beginner Dec 3 '11 at 22:10
@RomanB.: Sorry, that was misspelled a bit, fixed now. a[0][i] is the same as b[i] when you define T * b = &a[0][0];, which is what the OP proposes. –  Kerrek SB Dec 3 '11 at 22:13
Still don't understand. The question merely was if OP can pass either one dimensional array or two dimensional one. libFunc won't see the difference anyway, or? –  Beginner Dec 3 '11 at 22:17
@Kerrek I don't think the compiler is free to treat a[0][N] as an out of bound access, because it isn't one, and there is no undefined behaviour. Remember a[b] is defined as equivalent to *(a+b); what matters is if the element you finally end up is within the overall array or not. –  Alan Stokes Dec 3 '11 at 22:36
@AlanStokes: a[0] is an array of N elements, so a[0][N] accesses this array outside its bounds. –  Kerrek SB Dec 3 '11 at 22:52

You are basically screwed: The function expects a double *, so you should give it a double *.

The easiest and safer way to do that would be to use a wrapper. Something like:

template<size_t M, size_t N>
class Double2DArray
   std::vector<double> m_container ; // It could be a double[M * N]
                                     // But it could explode your stack
                                     // So let's use the heap
   public :
      // Etc.

         : m_container(M * N)
         // I assume the default you want is a vector already
         // filled with 0.0

      size_t getSizeM() { return M ; }
      size_t getSizeN() { return N ; }

      double & operator() (size_t p_m, size_t p_n)
         return m_container[p_m * N + p_n] ;

      double * data()
         return &(m_container[0]) ;

      // etc.
} ;

Of course, this code is not complete: At the very least, you should add the const versions of the accessors, probably handle copy-construction and assignment, etc.. I don't know your exact needs, so, your mileage may vary, but the core idea is there...

You could use this wrapper as follow:

void foo()
   Double2DArray<42, 13> my2DArray ;

   // etc.

   my2DArray(3, 5) = 3.1415 ;     // set some value
   double d = my2DArray(13, 2)  ; // get some value

   // etc.

   libFunc(my2DArray.data(), my2DArray.getSizeM(), my2DArray.getSizeN());

I would even overload libFunc to be safer:

template<size_t M, size_t N>
inline void libFunc(Double2DArray<M, N> & p_my2DArray)
   libFunc(p_my2DArray.data(), M, N);

This way I could be able to call it without needed to give it again and again the size of the array (it's so easy to mix M and N):

void foo()
   Double2DArray<42, 13> my2DArray ;

   // etc.


This is how I would use multidimensional arrays and feed it to a C-like API expected a contiguous array of doubles.

P.S.: If M and N are not know at compile time, you only need to remove the template, and make the M and N parameters of the constructor, and everything works (almost) the same.

share|improve this answer
So you've left out the initialization of m_container as an exercise for the reader? Also shouldn't libFunc(p_my2DArray, M, N); be libFunc(p_my2DArray.data(), M, N); ? –  Beginner Dec 3 '11 at 22:30
Also, am I allowed to pass a pointer to a member of a class out of that class and implicitly cast it like this? –  kalu Dec 3 '11 at 22:39
@Roman B. : So you've left out the initialization of m_container as an exercise for the reader? : This was not the most difficult/interesting part of the wrapper, IMHO. I believe the operator () overload, as well as the data accessors were more important to describe the usefulness of the wrapper. But I added the constructor anyway... –  paercebal Dec 3 '11 at 22:54
@Roman B. : Also shouldn't libFunc(p_my2DArray, M, N); be libFunc(p_my2DArray.data(), M, N); ? : You're right. Typo corrected. –  paercebal Dec 3 '11 at 22:54
@kalu : am I allowed to pass a pointer to a member of a class out of that class and implicitly cast it like this? : I believe you are refering to the return &(m_container[0]) ; code inside the data accessor. If you look at the std::vector's declaration, you'll see that the operator[] returns a reference to the item, so [0] returns a reference to the first double value. Then I take the address of this double value, and return it. This is a very well known vector "trick" to communicate with C API. –  paercebal Dec 3 '11 at 22:57

C++ uses row-major ordering so your multidimensional array is in fact a continuous 1-dimensional region in memory.
Even if declared for example 2-dimensional, it's accessed via index = x + y * height, so there should be no portability concerns...

The C++ documentation tells:

Multidimensional arrays are just an abstraction for programmers, since we can obtain the same results with a simple array just by putting a factor between its indices

(Here's also an explaination for visual c++)

share|improve this answer
The two scenarios in your reference either exclusively use multidimensional arrays or exclusively use regular arrays. There is no way to infer what will happen when I treat one as if it were the other. –  kalu Dec 3 '11 at 22:20
@kalu: please look at the section "multidimensional array" from cplusplus.com/doc/tutorial/arrays at the 6th. figure: int jimmy [3][5]; // is equivalent to int jimmy [15]; // (3 * 5 = 15) –  xmoex Dec 3 '11 at 22:24
The comment at the 6th figure is followed by an example that clarifies what is meant by "equivalent". As I mention in my comment above, the example does not clarify my question. This documentation would be helpful if we knew what, exactly, "equivalent" means in this context. –  kalu Dec 3 '11 at 22:49
you are right, it's not that clear what they're trying to say... i interpreted it as "you can use both for the same task". for a more precise answer you have to check the language specifications... –  xmoex Dec 3 '11 at 22:59
§ 8.3.4, section 6 to 9 of (C++ International Standard)[open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf] deal with multidimensional arrays. it seems that your topic isn't covered specifically by these sections even if sec. 6 could give a good hint... –  xmoex Dec 3 '11 at 23:25

Your Answer


