问题
I'm not sure if the history tag is relevant, but feel free to add it. I would presume the reason is historical, which is why I suggest this.
Why is it that I cannot declare a function signature such as the following?
void foo(int doubly_indexed_array[][]) {
...
}
which gives
$ gcc mem.c
mem.c:4: error: array type has incomplete element type
Why must you declare one of the dimensions as in the following?
void foo(int doubly_indexed_array[][10]) {
...
}
回答1:
You need to declare the second one and not only one. It has to do with memory layout, a 2-d array is stored contiguously in memory which means all the second dimension arrays are contigous.
So for int[2][2] the memory layout looks like(assuming initialization to 0):
[[0, 0][0, 0]]
Compiler has to know by how much to increment the pointer when indexing on the first dimension for example. So if an int array is named a,
a[i][j] is really (address of a) + i*sizeof(int)*second_dimension + j*sizeof(int)
All of this need to be known at compile time so the compiler can generate code.
回答2:
In essence, all arrays in C are one-dimensional. In order to be able to access an element by it's index, C needs to now the type of the elements.
Consider a one-dimensional array of ints. Since C knows the size of an int (say 4 bytes) it knows that to access element 50 it simply adds 50 * 4 = 200 bytes to the base address of the array. So it only needs to know the base address and the type of the elements, and not the overall number of elements (since C does not check for an out-of-range access, which would otherwise require the overall size).
Now a two-dimensional array is really a one-dimensional array whose elements are themselves arrays. In order to access an element in the "outer" array, you need to know its "type", which is an array of a certain type and size.
Consider a two-dimensional array declared as int a[100][10]. Since C knows that the type of the "outer" array is an array of 10 ints, it can calculate the position of the element (which itself is an array) at offset 50 by adding 50 * 4 * 10 to the base address. Note that the size of the "inner" array is necessary to find the position of the element. From that point it does the same thing as the previous example to find the position within the "inner" array of the requested int element.
Overall you have to declare the sizes of all the dimensions except the outermost one in order for C to be able to properly access the array.
回答3:
The declaration void foo(int array[][]) violates C 2011 (N1570) 6.7.6.2 1, which addresses array declarations and says, in part, “The element type shall not be an incomplete or function type.” Since array is an array of array of int, its element type is array of int, and it is incomplete because the number of int in that array is not specified.
Contrary to other answers, though, this number is not needed by the compiler at this point. You can make an equivalent declaration of void foo(int (*array)[]). There are two points to note about this:
- It does not violate the rule in 6.7.6.2 because it declares
arrayto be a pointer, rather than an array. Pointers are permitted to point to incomplete types. - If the first declaration were permitted, it would actually be the same as this declaration, because 6.7.6.3 says “A declaration of a parameter as “array of type” shall be adjusted to “qualified pointer to type”,…
However, the only way you can access elements with this declaration is in the form (*array)[i]. This is legal because the * operator may dereference a pointer to an incomplete type, so *array is the first row of the array, and then (*array)[i] is the ith element of that row.
You cannot properly access other rows of the array, because this requires an expression such as array[j][i], which requires performing pointer arithmetic on array, and pointer arithmetic requires that the pointer point to an object of complete type (because, for the compiler to figure out where objects beyond the one pointed to are, it must know how big the objects are, so it must have complete information about their size).
回答4:
Array in C is just like pointers, it doesn't include the size. Therefore if you don't provide the last dimension the compiler won't know how to calculate the address of the element
TYPE array[A][B];
&array[a][b] = (char*)array + a*sizeof(array[a]) + b
= (char*)array + a*(B*sizeof(array[a][b])) + b
= (char*)array + a*B*sizeof(TYPE) + b
As you see, if B is not declared then it have 3 unknown variables to solve when you're accessing array[a][b], that's the 2 dimension's index and B. That's why the compiler needs the last dimension size to produce code. Similarly it'll need the last n-1 dimensions of an n-dimensional array
来源:https://stackoverflow.com/questions/21691924/why-must-i-provide-a-dimension-when-passing-a-two-dimensional-array-to-a-c-funct