From what I remember arrays are always passed as pointers. For instance, the declaration:
void foo(int array[2][5]);
means for compiler exactly the same thing as:
void foo(int (*array)[5]);
You can say that these both forms are equivalent. Now, I wonder, why it is allowed then to declare it as:
void foo(int (*array)[]);
while not as:
void foo(int array[][]);
Take an example:
#include <stdio.h>
void foo(int (*p)[3]);
void bar(int (*p)[]);
int main(void)
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
foo(a);
bar(a);
return 0;
}
// The same as int p[][3] or int p[N][3] where N is a constant expression
void foo(int (*p)[3])
{
}
// Would it the same as int p[][] or int p[N][] (by analogy)?
void bar(int (*p)[])
{
}
It compiles fine and without warnings, but if I change bar
's declaration to:
void bar(int p[][]);
then it's an error.
Why C allows such "obscure" way to pass an array?
Arrays are not pointers, if you declare an array of pointers with unspecified size it's ok because it will store the addresses stored in the poitners contigously and the size of each element is known, but p[][]
would require the arrays to be contigous not their addresses and the size of the array is unknown so that's the problem.
To make it clear if you say int p[][]
the you don't know how far is p[0]
from p[1]
whereas in int (*p)[]
you know that the distance is the size of a pointer.
Arrays are converted to pointers but the are not pointers.
Arrays are usable as pointers, but they're more than pointers; they point to a number of things which have a size. That way, you can tell the compiler you're interested in the third or fifth element of your array, and it will calculate the location of that element by multiplying the size of one element by three or five to find an offset, and adding that offset to the address of the array.
C doesn't actually have multidimensional arrays. What it does have is arrays of arrays, which is pretty much the same thing. Say you have this:
int a[4][5];
In memory, this would look like this:
[0] |[1] |[2] |[3]
+-------------------|-------------------|-------------------|-------------------+
a | | | | | | | | | | | | | X | | | | | | | |
+-------------------|-------------------|-------------------|-------------------+
0 1 2 3 4 | 0 1 2 3 4 | 0 1 2 3 4 | 0 1 2 3 4 |
and you then try to access the element at index [2][2]
, then the system needs to perform the following calculation (conceptually):
In this case, the calculation is *(a + (2 * 5 * sizeof(int)) + (2 * sizeof(int)))
, giving *(a + 12*sizeof(int))
, which is indeed the correct offset from the starting pointer.
All that means is that the size of the inner array needs to be defined in order for the compiler to be able to do that calculation. If you don't define the size of any dimension (but the leftmost one) of your multidimensional array, you don't have a defined size, and the compiler will balk.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With