Reputation: 4016
I posted this question on programmers.stackexchange earlier today. I have always assumed that int (*)[]
does not decay into int **
in function parameters but I got multiple responses to my question that suggested that it does.
I have used int (*)[]
heavily in my function parameters but now I have become really confused.
When I compile this function using gcc -std=c99 -pedantic -Wall
void function(int (*a)[])
{
sizeof(*a);
}
I get this error message:
c99 -Wall -pedantic -c main.c -o main.o
main.c: In function ‘function’:
main.c:3:11: error: invalid application of ‘sizeof’ to incomplete type ‘int[]’
make: *** [main.o] Error 1
Which suggests that *a
has the type int []
and not int *
.
Can someone explain if things like int (*)[]
decays into int **
in function parameters and give me some reference (from the standard documents perhaps) that proves why it is so.
Upvotes: 15
Views: 1394
Reputation: 106012
Only array types converted to pointer to its first element when passed to a function. a
is of type pointer to an array of int
, i.e, it is of pointer type and therefore no conversion.
For the prototype
void foo(int a[][10]);
compiler interpret it as
void foo(int (*a)[10]);
that's because a[]
is of array type. int a[][10]
will never be converted to int **a
. That said, the second para in that answer is wrong and misleading.
As a function parameter, int *a[]
is equivalent to int **
this is because a
is of array type .
Upvotes: 18
Reputation:
In the case of int (*a)[]
, sizeof *a
does not work for one reason: there is no element count for the array. Without an element count, the size cannot be calculated.
As a consequence of this, any pointer arithmetic on a
will not work because it is defined in terms of the size of an object. Since the size is indeterminate for the array, you cannot use pointer arithmetic on the pointer itself. Array notation is defined in terms of pointer arithmetic, so sizeof a[0][0]
(or any expression involving a[n]
won't work whereas sizeof (*a)[0]
will.
This effectively means you can do very little with the pointer. The only things allowed are:
*
operatorIf your compiler supports variable-length arrays (VLAs), and you know the size, you could work around the issue by simply adding a line at the start of the function body as in
void
foo (int (*a0)[], size_t m, size_t n)
{
int (*a)[n] = a0;
...
}
Without VLAs, you must resort to some other measure.
It is worth noting that dynamic allocation isn't a factor with int (*)[]
. An array of arrays decays to a pointer to an array (like we have here), so they are interchangeable when passing them to a function (sizeof
and any _Alignof
or typeof
keywords are operators, not functions). This means that the array pointed to must be statically allocated: once an array decays to a pointer, no more decay occurs, so you can't say a pointer to an array (int (*)[]
) is the same as a pointer to a pointer (int **
). Otherwise your compiler would happily let you pass int [3][3]
to a function that accepts int **
instead of wanting a parameter of the form int (*)[]
, int (*)[n]
, int [][n]
, or int [m][n]
.
Consequently, even if your compiler doesn't support VLAs, you can use the fact that a statically allocated array has all of its elements grouped together:
void foo (int (*a0)[], size_t m, size_t n)
{
int *a = *a0;
size_t i, j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
// Do something with `a[i * n + j]`, which is `a0[i][j]`.
}
}
...
}
A dynamically allocated one-dimensional array that is used as a two-dimensional array has the same properties, so this still works. It is only when the second dimension is dynamically allocated, meaning a loop like for (i = 0; i < m; i++) a[i] = malloc (n * sizeof *a[i]);
to allocate each sub-array individually, that this principle not work. This is because you have an array of pointers (int *[]
, or int **
after array decay), which point to the first element of an array at another location in memory, rather than an array of arrays, which keeps all of the items together.
So:
no, int (*p)[]
and int **q
cannot be used in the same way. p
is a pointer to an array, which means all items are grouped together starting the address stored in p
. q
is a pointer to a pointer, which means the items may be scattered at different addresses that are stored in q[0]
, q[1]
, ..., q[m - 1]
.
sizeof *p
doesn't work because p
points to an array with an unknown number of elements. The compiler cannot calculate the size of each element, so operations on p
itself are very limited.
Upvotes: 2
Reputation: 137315
N1256 §6.7.5.3/p7-8
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the
[
and]
of the array type derivation. If the keywordstatic
also appears within the[
and]
of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.8 A declaration of a parameter as ‘‘function returning type’’ shall be adjusted to ‘‘pointer to function returning type’’, as in 6.3.2.1.
int (*)[]
is "pointer to array of int
". Is it "array of type"? No, it's a pointer. Is it "function returning type"? No, it's a pointer. Therefore it does not get adjusted.
Upvotes: 7
Reputation: 11058
int (*)[]
is a pointer to an array of int
.
In your example, *a
can decay to int*
. But sizeof(*a)
doesn't do decaying; it is essentially sizeof(int[])
which is not valid.
a
can not decay at all (it's a pointer).
Upvotes: 7