Home > front end >  Why does a two-dimensional array become a one-dimensional array after passing it to a function?(C
Why does a two-dimensional array become a one-dimensional array after passing it to a function?(C

Time:04-27

I'm making a simple Snake game. When making a map, my definition of the map is as follows

int map[25][25] = { 0 };

for (int i = 0; i < 25; i  )//Set the boundary to - 2
{
    map[0][i] = -2;
    map[24][i] = -2;
}
for (int i = 1; i < 25; i  )//Set the boundary to - 2
{
    map[i][0] = -2;
    map[i][24] = -2;
}

Then I made a function to simulate the motion of the snake。(The first parameter is the class I created: snake,The second is its moving direction. The key is the third parameter, the map array I put in.)

void snake_move(Snake snake1, int direction, int map[][25])

Then I made a call to the function.(The third parameter is the two-dimensional array pointer I passed in)

snake_move(snake1, direction, map); 

Then the following figure appears enter image description here

I found that it was a two-dimensional array before the function call,which is as follows enter image description here

Why does this happen and how to solve this problem? I look forward to your reply・v・

CodePudding user response:

You cannot pass built-in arrays like this to functions. snake_move(), even though it appears to have an argument that looks like a 2D array, it actually takes a pointer to a 1D array. This:

void func(int map[][25]);

Is actually equivalent to:

void func(int (*map)[25]);

map is a pointer to an array of 25 int elements. When you call that function:

func(map);

The map array "decays" to a pointer that points to its first element.

This is an unfortunate consequence of C 's compatibility with C.

To avoid issues like this, use std::array (for fixed-size, static allocation of elements), or std::vector (for dynamically allocated elements.)

To get a 2D array, you need to use an array of arrays or a vector of vectors. For an array, that means:

std::array<std::array<int, 25>, 25>

This means "an array containing 25 arrays of 25 int elements.

It's a good idea to make snake_move take a const reference to avoid an unnecessary copy of the whole array. So:

#include <array>

void snake_move(
    Snake snake1, int direction,
    const std::array<std::array<int, 25>, 25>& map);

// ...

std::array<std::array<int, 25>, 25> map{};

for (int i = 0; i < 25; i  ) {
    map[0][i] = -2;
    map[24][i] = -2;
}

for (int i = 1; i < 25; i  ) {
    map[i][0] = -2;
    map[i][24] = -2;
}

snake_move(snake1, direction, map);

If snake_move() needs to modify the passed array, then remove the const.

To reduce the need to write the type over and over again, you can use an alias (with the using keyword):

using MapType = std::array<std::array<int, 25>, 25>;

void snake_move(Snake snake1, int direction, const MapType& map);

// ...

MapType map{};
// ...

The {} in the map declaration will initialize all values to zero. You can also use:

MapType map = {};

which does the same.

CodePudding user response:

You can actually keep the dimension without using std::array

void snake_move(Snake snake1, int direction, int (&map)[25][25]);

https://godbolt.org/z/EYz7hzjTj


Also note it's not a 1D array (i.e. map[0] is not -2), the debug window does recognize and shows it's a int[25]*, it probably just have some bug that fail to display it in the correct format.

CodePudding user response:

Why does this happen

Because of type decay. In particular, in many contexts (including when appearing as a parameter to a function), an array decays to a pointer to its first element. For example:

  1. The type int [6] decays to int*

  2. The type int *[6] decays to int**.

  3. The type double [10] decays to double*.

  4. The type int [5][6] decays to int (*)[6].

Thus, in you example, the third parameter int map[][25] is actually a pointer to an array of size 25 with elements of type int, ie int (*)[25].


how to solve this problem?

You can use std::array, as shown below:

void snake_move(Snake snake1, int direction, 
//----------------------------vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv------->std::array used
                              std::array<std::array<int, 25>,25> map) 
{
    
}

std::array<std::array<int, 25>,25> map; //sta::array used

If the function snake_move() doesn't change the passed std::array, and to avoid unnecessary copying, you can take the std::array as a reference to const:

void snake_move(Snake snake1, int direction, 
                              const std::array<std::array<int, 25>,25>& map)
//----------------------------^^^^^-----------------------------------^----->lvalue reference to non-const std::array<std::array<int, 25>,25> 
{
    
}
  • Related