I am going to assume the function foo in your example actually wants a 2-D array of int, with MAX columns and an unspecified number of rows. This works in C and C++ because of how the rows lay out in memory. All the elements in row N+1 appear contiguously after all the elements in row N.
The syntax int arr[][MAX] asks for a pointer to the first element of such a 2-D array, not an array of pointers to rows. I'll assume you want the 2-D array, and not an array of pointers.
First, you need to correctly allocate your elements. You haven't specified what the leftmost dimension of arr[][MAX] is, or where it comes from. I'll assume it's in the variable dim here:
int (*ptr)[MAX]; /* pointer first element of an int[][MAX] array */
/* Allocate a 2-D array of dim * MAX ints */
ptr = (int (*)[MAX]) malloc( dim * MAX * sizeof(int) );
Then, to call your function, just do foo( ptr ) and it'll work without errors or warnings.
To make your code cleaner (especially if you're using many of these 2-D arrays), you might consider wrapping the pointer type in a typedef, and writing a small function to allocate these arrays.
typedef int (*int_array_2d)[MAX];
int_array_2d alloc_int_array_2d( int dim1 )
{
return (int_array_2d) malloc( dim1 * MAX * sizeof(int) );
}
That way, elsewhere in your code, you can say something much simpler and cleaner:
int_array_2d ptr = alloc_int_array_2d( dim );
Use the type system to your advantage. The C and C++ syntax for the type and the typecast are ugly, and unfamiliar to most people. They look strange due to the precedence of * vs. []. If you hide it in a typedef though, it can help keep you focused on what you're trying to do, rather than understanding C/C++'s weird precedence issues that arise when you mix arrays and pointers.