Passing 2d Array of objects into function

I'm trying to code Conway's game of Life on a Raspberry Pi Pico using the Arduino IDE and C++.

When I try to pass the 2d array of individual cells into the function, the compiler returns an error message of "cannot convert Conway_Cell[64][32] into Conway_Cell(*)[32]. I can't find any information about why the function is doing this. I believe it's a pointer issue but am not sure. I haven't knowingly introduced pointers anywhere in the project.

I know that the code is inefficient and unoptimized, but I wanted to get it working before worrying about opimisation.

void GameOfLifeUpdate(Conway_Cell gridmain[col][row], Conway_Cell gridback[col][row], Adafruit_Protomatter matrix){
  gridCurrent[col][row] = gridmain[col][row];
  gridStorage[col][row] = gridback[col][row];
  for (int i = 0; i < col; i++) {
    for (int k = 0; k < row; k++){
      int neighbours = 0;
      while (neighbours < 5){
        if(i-1 > 0 & k+1 < 64 ) {neighbours += gridCurrent[i-1][k+1].State;};
        if(i-1 > 0)             {neighbours += gridCurrent[i-1][k].State;};
        if(i-1 > 0 & k-1 > 0)   {neighbours += gridCurrent[i-1][k-1].State;};
        if(k+1 < 64)            {neighbours += gridCurrent[i][k+1].State;};
        if(k-1 > 0)             {neighbours += gridCurrent[i][k-1].State;};
        if(i+1 < 64 & k-1 > 0)  {neighbours += gridCurrent[i+1][k-1].State;};
        if(i+1 < 64)            {neighbours += gridCurrent[i+1][k].State;};
        if(i+1 < 64 & k+1 < 64) {neighbours += gridCurrent[i+1][k+1].State;};
      }
      if(gridCurrent[i][k].State == true){
        switch (neighbours){
          case 0 && 1: 
            gridStorage[i][k].Die();
            break;
          case 2 && 3:
            gridStorage[i][k].Live();
            break;
          case 4:
            gridStorage[i][k].Die();
            break;
          default:
            break;
        }
      }
      else if (neighbours == 3){
        gridStorage[i][k].Live();
      }
    }
  }
  gridCurrent[col][row] = gridStorage[col][row];
  for (int i = 0; i < col; i++) {
    for (int k = 0; k < row; k++){
      if(gridCurrent[i][k].State == true){
        matrix.drawPixel(i, k, matrix.color565(255, 255, 255));
      }
      else{
        matrix.drawPixel(i, k, matrix.color565(169, 169, 169));
      }
    }
  }
}

void loop() {
  GameOfLifeUpdate(gridCurrent[col][row], gridStorage[col][row], matrix)
}

In C/C++, array names are pointers. But you don't need to worry about that in this case.

This is valid, and is the no nonsense approach I prefer. Array dimensions must be fixed at compile time.

#define ROWS 4
#define COLS 5

void func(int array[ROWS][COLS])
{
  int i, j;

  for (i=0; i<ROWS; i++)
  {
    for (j=0; j<COLS; j++)
    {
      array[i][j] = i*j;
    }
  }
}

void setup()
{
  int x[ROWS][COLS];
  func(x);
}
void loop(){}

Being that this is C++, how about passing by reference?

void func(int (&array)[ROWS][COLS]) {

What you're starting to do here is pass an individual cell -- a single element of the 2-D array, and an invalid one, just past both the last column and last row -- to the function. So the compiler is complaining: can't convert this specific element to a Conway_Cell(*)[32]: a pointer to a column of 32 rows of cells. This leads to the function declaration

The col is actually ignored. If it has a value because it is a constant or #defined macro, it is allowed in the declaration of the argument, but is not a value "passed into" the body of the function. The row is used, but not passed in either.

Not only is the array name a pointer, but the compiler needs to know the size of each element. When declaring a multi-dimensional array as a function argument, that means the dimensions of every dimension except the first

  • uint16_t *x0 -- two bytes each
  • uint16_t x1[] -- two bytes each
  • uint16_t x2[][3] -- six bytes each
  • uint16_t x3[][3][4] -- 24 bytes each

This is so you can do the now-frowned-upon pointer arithmetic, like x3++ to point to "the next one". When declaring the storage of the original array, you need all the dimensions.

So it may be misleading to use col as part of the function argument. The compiler is not obligated to warn you that an array reference is out of bounds, even if it is obvious at compile time. And certainly there is no runtime check.

As for declaring the argument as a reference

  • the size of the first dimension is now required
    • unlike when it was ignored and you could have nothing or anything, even 0, the caller's dimension must match
  • pointer arithmetic is no longer allowed

Either way, since row is already defined elsewhere, this call should work

void loop() {
  GameOfLifeUpdate(gridCurrent, gridStorage, matrix);
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.