Pass 2d array to function?

Hello,
As far as I understand, this is correct/fine code, aside from the "8" being hard-coded (it normally should not be)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void ShowArray(int* a)
{
  for(int col = 0; col < 8; ++col)
  {
    drawFunc(a[col]);
  }
}

int main(int argc, char* args[])
{
  //..
  map[8];
  ShowArray(map);
  //..
}

As far as I know, the above code sends the ptr to the func, not the values individually (which is what I want)

So how do I do this for a contiguous 2d array (i.e. not an array of pointers using 'new'!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void ShowArray(int*??? a)
{
  for(int row = 0; row < 8; ++row
  {
    for(int col = 0; col < 8; ++col)
    {
      drawFunc(a[row][col]);
    }
  }
}

int main(int argc, char* args[])
{
  //..
  map[8][8];
  ShowArray(map???);
  //..
}

Thank you very much!
Add another * for each dimension of the array.
Forgot to say that that was the first thing I tried (since it seems intuitive to try that), but it doesn't work.. unless I'm misunderstanding something.

so, ShowArray(int** a) ?


ShowArray(map)
gets "argument int* incompatible with parameter int**"

ShowArray(*map)
gets "argument int incompatible with parameter int**"

ShowArray(&map)
gets "argument int(*)[8] incompatible with parameter int**"

Obviously I don't have enough understanding of what needs to be done, so any explanation would be appreciated.
one way is pass by reference
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void ShowArray(int (&a)[8][8])
{
  for(int row = 0; row < 8; ++row)
  {
    for(int col = 0; col < 8; ++col)
    {
      drawFunc(a[row][col]);
    }
  }
}

int main()
{
  int map[8][8];
  ShowArray(map);
}


another is pass by pointer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void ShowArray(int (*a)[8])
{
  for(int row = 0; row < 8; ++row)
  {
    for(int col = 0; col < 8; ++col)
    {
      drawFunc(a[row][col]);
    }
  }
}

int main()
{
  int map[8][8];
  ShowArray(map);
}

Last edited on
Thank you very much, I tried passing by reference and it works, however, I have a question:

if I'm passing "map" into ShowArray, and map is an entire array, does this mean I'm passing the entire array (one int at a time) through the stack, into the reference?
does this mean I'm passing the entire array (one int at a time) through the stack, into the reference?

no, "map" within ShowArray and "map" within main() are two names of the same object - that's the point of pass-by-reference.
Note that this form

void ShowArray(int (*a)[8])

is identical to

void ShowArray(int a[][8])

as far as the compiler is concerned. They are not seen as distinct overloads.

(for what it's worth,

void ShowArray(int a[8][8])

void ShowArray(int a[1][8])

void ShowArray(int a[1024][8])

...

are all also seen as the same overload, as the compiler totally ignores the first dimension, just to confuse people.)

As the (*)[8] and [][8] forms put no constraints on the first dimension (as does the reference form), you should really pass the first dimension as well as the array.

Also, to complete the set, even though I've never seen this form used outside of exercises, you can use an array pointer. See code below.

By the way, your orig. question is a bit ambiguous when it comes to what you want?

As far as I know, the above code sends the ptr to the func, not the values individually (which is what I want)

You want to send the values individually??

Andy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void ShowArray(int (*a)[8][8])
{
  for(int row = 0; row < 8; ++row)
  {
    for(int col = 0; col < 8; ++col)
    {
      drawFunc((*a)[row][col]); // derference a
    }
  }
}

int main()
{
  int map[8][8];
  ShowArray(&map); // pass address of map

  return 0;
}
Last edited on
The better way is to declare the function the following way

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iterator>

void drawFunc( int x ) { /* some processing with x */ }

void ShowArray( const int ( *first )[8], const int ( *last )[8] )
{
   for ( ; first != last; ++first )
   {
      for ( int x : *first ) drawFunc( x );
   }
}

int main()
{
   int map[8][8];

   ShowArray( std::begin( map ), std::end( map ) );
}
Cubbi, Andy, Vlad:
Thank you so much for the information and advice. I've learned a lot, and I've always been a bit baffled at proper syntax for sending a ptr to a 2D array, so thank you.

To answer some questions:
You want to send the values individually??

I worded that part ambiguously -- oops. I meant, "By doing it this way, am I pushing the entire array onto the stack? Because I'd like to avoid that if possible (i.e. I'd highly prefer if the only thing sent through the stack was one pointer/address when that function is called once.)

By the way, your orig. question is a bit ambiguous when it comes to what you want?

Also, I may be able to clear something up by saying that the size of the two dimensions would also be passed into the function, so that it would support multiple sized 2D arrays. So something like: ShowArray(map, 8, 5) or ShowArray(table, 6, 31). I hard-coded the 8's because I was more concerned with the passing the ptr properly and figured I'd cross the bridge of having variable sizes when I come to it. As to exactly what I want, the function, in reality, is a SaveFunc which (hopefully) takes a ptr to the 2D array (which may be different x,y, and writes it to a binary file (which is already implemented and working).

Vlad, thank you for the suggestion, but, if possible, I would like to use the most basic-as-possible datatypes, mostly for myself, to have a project that would be a good reference for bare foundations work. (I'm even using char arrays instead of strings so that I never forget how to implement them without issue)

-

So, with the addition of wanting variable sized dimensions, is it still possible? How could I use the vars passed in, in the proper places? I almost feel that I would have to ... cast after the fact? Am I wrong?

1
2
3
4
5
6
7
8
9
10
11
12
ShowArray(int* ptr, int x, int y)
{
   int (*arr)[][x] = &ptr;

   for(int row = 0; row < y; ++row)
   {
      for(int col = 0; col < x; ++col)
      {
         func(arr[row][col]);
      }
   }
}
(I'm even using char arrays instead of strings so that I never forget how to implement them without issue)

It's like using addition instead of multiplication so that you never forget how to multiply by hand.

saying that the size of the two dimensions would also be passed into the function, so that it would support multiple sized 2D arrays

the low-level C-style 2D arrays have their sizes as parts of their types, which means to pass them into a function, you need a function template:

1
2
3
4
5
6
7
8
9
10
11
template<std::size_t X, std::size_t Y>
void ShowArray(int (&arr)[X][Y])
{
   for(int row = 0; row < Y; ++row)
   {
      for(int col = 0; col < X; ++col)
      {
         func(arr[row][col]);
      }
   }
}


or you could use (or build, if you like) a matrix type that uses 1D storage internally and exposes a row,col indexing in the interface, so that you could write the usual
1
2
3
void ShowArray(const Matrix& m) {
[...]
func(m[row][col]) // or func(m(row, col)), depending on the library you're using) 
If I set up the function call as such:

ShowArray(&array, numCols, numRows);
or
ShowArray(array, numCols, numRows);

could I still get "ShowArray" to work as discussed?
could I still get "ShowArray" to work as discussed?

I assume you mean as sort of shown in your last mail? There have been several different approaches suggested in this discussion...

Note that Cubbi's template approach is the best way to go if you have to use a C-style array in C++ code, as you can't pass dimensions that are out of step with the array. And the "Matrix" class far better (esp. as they can be coded to size dynamically, if required.)

But you can take advantage of the the fact that the elements of a 2D array are stored contiguously in row major order and do this (which is what a Matrix class would usually do internally, and what the compiler is doing behaind the scenes for you when you use operator[] on an array.)

1
2
3
4
5
6
7
8
9
10
void ShowArray2D(int* ptr, int x, int y)
{
   for(int row = 0; row < y; ++row)
   {
      for(int col = 0; col < x; ++col)
      {
         func(arr[row * x + col]); // explicilty do the maths the
      }                            // compiler normally does for you
   }
}


calling it like this

1
2
3
   int map[8][8];
   ShowArray2D(&map[0][0], 8, 8); // pass the address of the first array
                                  // element plus dimensions 


The one disadvantage of the template approach is that a different version of the function will be instantiated for each set of array dimensions you use. Not a big deal with a small functions, or if you only use a limited number of array sizes, but it could add up. So you could make the template function a wrapper of the "linear" function.

1
2
3
4
5
template<std::size_t X, std::size_t Y>
void ShowArray(int (&arr)[X][Y])
{
    ShowArray2D(&arr[0][0], X, Y);
}


Andy
Last edited on
Topic archived. No new replies allowed.