1

I just came across this function call/declaration pair in C, and I'm a bit confused (I'm a newbie here, but I haven't seen this addressed in any of the material I've been using to learn). The function declaration is given as bool read_matrix(double a[][M], int n, int m), but it is called by read_matrix((double (*)[M]) a, n, m). (M is an integer set by #define.) How do these parameters line up with one another? For that matter, what type of object is (*)[M]?

Thanks for clearing up the confusion.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • `(*)[M]` is a [pointer to an array](https://stackoverflow.com/questions/859634/c-pointer-to-array-array-of-pointers-disambiguation) and since [arrays decay to pointers](https://stackoverflow.com/questions/1461432/what-is-array-to-pointer-decay) when passed to a function, an array of arrays like `a[N][M]` decays to a pointer to an array like `(*ptr)[M]` – user3386109 May 20 '20 at 19:14

2 Answers2

1

When a function parameter declared with an array type like in this function declaration

bool read_matrix(double a[][M], int n, int m);

then it is adjusted by the compiler to pointer to the element type.

So this function declaration is equivalent to the declaration

bool read_matrix(double ( *a )[M], int n, int m);

On the other hand array designators used in expressions as for example as an argument are converted to pointers to their first elements.

So if in a caller of the function you have an array declared like

double a[N][M];

then passed to the function like

read_matrix( a, N, M );

it is converted to pointer to its first element of the type int ( ^ )[M].

As for the casting in the call you showed

read_matrix((double (*)[M]) a, n, m)

then if a is an array declared as shown above then the casting is redundant. This conversion takes place implicitly.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.

When you pass an array expression as a function argument, what the function actually receives is a pointer value:

void foo( T *a ) // equivalent to T a[] and T a[N]
{
  ...
}

int main( void )
{
  T arr[N];
  ...
  foo( arr );
  ...
}

As a "convenience" C allows you to use array notation for a function parameter declaration, but be aware it will be "adjusted" to be a pointer declaration because the parameter is a pointer value, not an array - T a[N] and T a[] will be interpreted as T *a. Note that this is only true in a function parameter declaration, not a regular variable declaration.

Now, just for giggles, replace T with the array type double [M]. So instead of being an N-element array of T, arr is now an N-element array of M-element arrays of double:

int main( void )
{
  double arr[N][M];
  ...
  foo( arr );
  ...
}

In the call to foo, the expression arr "decays" from type "N-element array of M-element arrays of double" to "pointer to M-element array of double", or double (*)[M]. So our declaration of foo looks like this:

void foo( double (*a)[M] ) // equivalent to double a[][M] and double a[N][M]
{
  ...
}

And this is why the two seemingly different declarations are equivalent - in the context of a function parameter declaration, double a[][M] is interpreted as double (*a)[M]. Again, this is only true for function parameter declarations, not regular variable declarations.

John Bode
  • 119,563
  • 19
  • 122
  • 198