If you look at the underlying memory structure you will see why the compiler isn't letting you pass int[m][n]
in place of int**
.
If you have int**
, what you pass is a pointer to an array of pointers to arrays of int
s. The memory therefore looks like:
int** -|
V
[ int*, int*, int*, ...]
V V V
int[] int[] int[] ...
Notice that the int[]
s do not necessarily have to be continuous between themselves.
If you have an int[m][n]
, the memory looks like this:
int[m][n]
|
V
[ [ int, int, int, ...] m times,
[ int, int, int, ...] m times,
[ int, int, int, ...] m times,
... ] n times
You have a contiguous block where the two arrays occupy all of the memory, and there really is no pointer in the array.
So, while an array might be convertible to a pointer under certain conditions, a pointer to an array most certainly isn't convertible to a pointer to a pointer.
With this insight you can also see why the compiler will sometimes let you use an array of unknown bound (int[]
), but will never let you use it in a matrix unless it is the last array declarator (int[5][]
is legal, int[][5]
is not), because in this case it cannot know how big each element of the array with length 5 is.
Here's how I would go about this: make the function a template
and make the dimensions of the matrix (m and n) template parameters, you can then take a reference to an array of arrays (matrix) with those dimensions as parameter and don't have to worry about pointers to anything. This also avoids the use of variable-length-arrays (a non-standard extension to C++) since the matrix bounds are known at compile time. This means you have to make uniquePaths
a template, too.