What style of array declaration you use depends on how much you know at compile time.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROWS 5
#define COLS 10
void foo ( int array[ROWS][COLS], int rows, int cols ) {
// just use array[r][c] here
}
void bar ( int (*var_rows)[COLS], int rows, int cols ) {
// just use var_rows[r][c] here
}
void baz ( int **var_rowscols, int rows, int cols ) {
// just use var_rowscols[r][c] here
}
int main(){
int array[ROWS][COLS]; // both known at compile time
int (*var_rows)[COLS]; // only COLS known at compile time
int **var_rowscols; // nothing known at compile time
int nRows = 20, nCols = 50; // run-time sizes
var_rows = malloc( nRows * sizeof(*var_rows) );
var_rowscols = malloc( nRows * sizeof(*var_rowscols) );
for ( int r = 0 ; r < nRows ; r++ ) {
var_rowscols[r] = malloc( nCols * sizeof(*var_rowscols[r]) );
}
foo(array,ROWS,COLS);
bar(var_rows,nRows,COLS);
baz(var_rowscols,nRows,nCols);
return 0;
}
Some things to note:
1. The parameter declaration is a copy/paste of the variable declaration in main.
2. [r][c] notation works regardless of whichever style of 2D array you choose to create.
3. The actual parameter passed is just the variable name itself - no mysterious & or * needed.