5

I have constant multi-dimensional arrays of different sizes. I would like to pass them to a function. However, I would get the error missing subscript, the sizes of the arrays are different so I can't put the subscript in the array parameter. What is the solution to this problem?

Here is an example code. The actual arrays are bigger.

//ARRAY1
const double ARRAY1[3][2][2] =
{
    {
        {1.0,1.0},
        {1.0,1.0},
    }
    ,
    {
        {1.0,1.0},
        {1.0,1.0},
    }
    ,
    {
        {1.0,1.0},
        {1.0,1.0},
    }
}
//ARRAY2
const double ARRAY2[2][2][2] =
{
    {
        {1.0,1.0},
        {1.0,1.0},
    }
    ,
    {
        {1.0,1.0},
        {1.0,1.0},
    }
}

//How to declare the parameter?
double SomeFunctionToWorkWithBothArrays(const double arr[][][])
{

}
1
  • Please pick one language not two. C and C++ answers to this question will be very different. Commented Mar 21, 2017 at 10:29

8 Answers 8

14

You could use a template.

template<size_t first, size_t second, size_t third> 
double SomeFunction(const double (&arr)[first][second][third]) {
    return first + second + third;
}

This function takes a reference to a three-dimensional array of doubles where all dimensions are known at compile-time. It's actually possible to take this reference via template, if desperate.

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you guys for your help. I will use templates for it.
@DeadMG : not tricky, but that is what came to my mind when I wrote that comment :P
Don't see why it's tricky. It's pretty basic use of templates!
One thing to watch is that each version of the function will get its own implicit instantiation of the function code.
@Martin York: A solution is to call a non-template function from within the template-wrapper and submit it the pointer and the three array sizes as function parameters...although I don't know if the layout of multidimensional arrays is defined by the standard!? If not it would be relying on implementation specific behaviour.
5

Use std::vector instead of arrays. Vectors know their own size, so that would be no problem. You can use vectors of vectors as multi-dimensional arrays.

4 Comments

That's quite a bit of heap overhead for the dynamic size he clearly doesn't need.
@DeadMG: true, and indeed I 'm answering a slightly different question here. But still, IMHO "go with vectors" is a good rule of thumb.
Could have answered vector of arrays (i.e., boost/std:: array), like vector<array<array<double, 2>, 2>>
It's barely any overhead actually, and dynamic allocation doesn't mandate the use of any 'heap'. However, sticking with static allocation where possible is indeed preferred. :)
3

You can either use std::vector (whose size is variable and doesn't need to be specified in the type), or you can stick with static allocation and use templates:

template <size_t X, size_t Y, size_t Z>
double SomeFunctionToWorkWithBothArrays(const double (&arr)[X][Y][Z])
{
   // A different version of this function will
   // exist for each combination of X, Y and Z.
}

(In this example I have assumed that all three dimensions may differ.)

Also note that I am passing the array by reference; you actually cannot pass an array by value, as the argument will collapse into a pointer, and with multi-dimensional arrays this gets a little complicated.

Hope this helps.

Comments

2

You can use the boost::array template class and a template function declaration to handle this.

EDIT: Just to add an example:

template<typename T, std::size_t I, std::size_t J, std::size_t K>
void MyFunction(const std::array<std::array<std::array<T, K>, J>, I>& data)
{
    // do something here
}

which you would call in the manner of:

std::array<std::array<std::array<T, 4>, 2>, 3> data; // which hopefully you have typedef'd somewhere to make the code more readable
MyFunction<double, 3, 2, 4>(data);

Comments

1

I know of 2 approaches for this problem:

  1. Use a sentinel value as last entry to the array, eg. {-1.0,-1.0}. You always just need to check the first value in the next major dimension
  2. Add additional parameter(s) to the function, which specifies the size of dimension(s), eg. x, y, z or struct dim { int x, y, z};

Regards,

Martin.

Comments

1

If it is only the first dimension that is variable (the other dimensions are the same for all arrays), then you can still pass the arrays to the same function, because you are allowed to leave the first array dimension out in a function parameter.

double SomeFunctionToWorkWithBothArrays(const double arr[][2][2])
{

}

If the other dimensions can change as well, then you will have to use different functions, possibly created from a single template, as shown in the answer from @DeadMG.

1 Comment

True, but you should really mention that with this approach you need to pass the size of the first dimension as a parameter.
0

If and only if the arrangement of multi-dimensional arrays is defined by the standard (Question to the standards gurus) you could do the following:

in your header:

double SomeFunctionToWorkWithBothArraysInt(double const *data, int x, int y, int z);

template <size_t X, size_t Y, size_t Z>
double SomeFunctionToWorkWithBothArrays(double const (&arr)[X][Y][Z]) {
  SomeFunctionToWorkWithBothArraysInt(&arr, X, Y, Z);
}

in your .cpp file:

double SomeFunctionToWorkWithBothArraysInt(double const *data, int x, int y, int z) {
  double res = 0.0;
  for (int xp = 0; xp < x; xp++) {
    for (int yp = 0; yp < y; yp++) {
      for (int zp = 0; zp < z; zp++) {
        res += data[(zp * y + yp) * x + xp]; // !!!ATTENTION!!!: This may be wrong if the array arrangement is different!
      }  
    }  
  }

  return res;
}

The advantage is that your "business logic" is not instantiated with each instantiation of the template function and is not exposed via the header file.

1 Comment

The arrangement of multi-dimensional arrays is defined by the standard. The only quibble is that your call should be: SomeFunctionToWorkWithBothArraysInt(&arr[0][0][0], X, Y, Z). The value of the address will be unchanged, but the type will now be "pointer to const double" rather than "pointer to array (size Y) of array (size Z) of double" or "pointer to array (size X) of array (size Y) of array (size Z) of double" (I can't remember which of those two it will be.)
0

In the C language, simply define your function as

double func (size_t x, size_t y, size_t z, double arr[x][y][z])

This is possible because C (unlike C++) has variable-length arrays.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.