Best way to pass a 2d array to functions which size is unknown at compile time in pure C I've been wondering for some time what the best way to pass a 2d array to functions is. I know that arrays, passed to functions, decay into pointers, so int arr[25] would become int *arr inside a function. The problem is with 2d arrays, int arr[5][5] would not become int **arr. Instead I've been taught to pass it like this: int (*arr)[5]. The problem with that is that the final square brackets need to have a size parameter inside and it needs to be known at compile time.

I've looked around and found this answer which, I believe, has the best solution. The idea is to pass the 2 dimensions separately and the location of the data. So, the function's signature would be like this:

void print(void *arr, size_t rows, size_t cols);

Then, we create a temporary array, which we can use conventionally, like this:

int (*temp)[cols] = (int (*)[cols]) arr;

I wrote some code to test this and it works.

#include &lt;stdio.h&gt;

void fill(void * arr, size_t rows, size_t cols, int val);
void print(void * arr, size_t rows, size_t cols);

int main(void) {
  size_t iArr = 5, jArr = 3;
  int arr[iArr][jArr];
  fill(arr, iArr, jArr, 0x45);
  print(arr, iArr, jArr);
  return 0;
}

void fill(void * arr, size_t rows, size_t cols, int val)
{
  int (*temp)[cols] = (int (*)[cols])arr;
  for(size_t i = 0; i &lt; rows; i++)
  {
    for(size_t j = 0; j &lt; cols; j++)
    {
      temp[i][j] = val;
    }
  }
  arr = temp;
}

void print(void * arr, size_t rows, size_t cols)
{
  int (*temp)[cols] = (int (*)[cols])arr;
  for(size_t i = 0; i &lt; rows; i++)
  {
    for(size_t j = 0; j &lt; cols; j++)
    {
      printf("%3d ", temp[i][j]);
    }
    putchar('\n');
  }
}


This can also be tested here. I'm curious whether this will work always without errors. I tested it with all kinds of sizes and, again, no problem there. Can this be improved further? Could there be any edge cases where this breaks (checks for valid arguments or making sure the size passed doesn't exceed the stack size are omitted here, as that's not the point of this question).
Type-wise, it is ok to go from void pointers to array pointers and back. As long as the "effective type" is an int array of the specified size. Void pointers do however have non-existent type safety, so they should be avoided for that reason.

The best way is rather to use an array and let the compiler "adjust" it to an array pointer between the lines:

void fill (size_t rows, size_t cols, int arr[rows][cols], int val);


The VLA syntax requires that rows and cols exist, so arr must be declared on the right side of them in the parameter list. Please note that this is still a pointer and not a whole VLA passed by value - we can't pass arrays by value in C.

Fixed example:

#include &lt;stdio.h&gt;

void fill(size_t rows, size_t cols, int arr[rows][cols], int val);
void print(size_t rows, size_t cols, int arr[rows][cols]);

int main(void) {
  size_t iArr = 5, jArr = 3;
  int arr[iArr][jArr];
  fill(iArr, jArr, arr, 0x45);
  print(iArr, jArr, arr);
  return 0;
}

void fill(size_t rows, size_t cols, int arr[rows][cols], int val)
{
  for(size_t i = 0; i &lt; rows; i++)
  {
    for(size_t j = 0; j &lt; cols; j++)
    {
      arr[i][j] = val;
    }
  }
}

void print(size_t rows, size_t cols, int arr[rows][cols])
{
  for(size_t i = 0; i &lt; rows; i++)
  {
    for(size_t j = 0; j &lt; cols; j++)
    {
      printf("%3d ", arr[i][j]);
    }
    putchar('\n');
  }
}