I understood that we can omit the first dimension but other dimensions are inevitable to be specified.
Yes. When you declare an array, the element type must be a complete type. This is a formal constraint specified in paragraph 6.7.6.2/1 of the standard, so conforming compilers must diagnose violations.
But so what? You're asking about the declaration of parameter p
in ...
void f1(int (*p)[]){
... which has a pointer type. Specifically, it is a pointer to an array of an unknown number of ints. That array type omits only the first dimension, which, as you know, is allowed, though it makes the type an incomplete one. Pointers to incomplete types are allowed (and are themselves complete types), with type void *
being the poster child. Furthermore, type int(*)[]
is compatible with the type of the argument you are passing, which is int(*)[3]
(not int[3][3]
).
Why does C allow such kind of declaration?
Why shouldn't it? I mean, incomplete types are a bit weird, but they serve a useful purpose. The parameter declaration you present is consistent with C's requirements.
If it is very certain that it is going to throw an error on pointer's use then why is it not throwing error at the time of declaration itself? Why wait for pointer's use to throw an error?
Because only some uses of the pointer are erroneous. You can convert it to an integer or to another pointer type, for instance, or assign it to a variable of compatible type. In fact, although C does not define the behavior of dereferencing pointers to other varieties of incomplete types, it does allow you to dereference pointers to incomplete array types.
Is there any specific reason for allowing such a declaration?
Consistency? Usefulness? Your question seems predicated on the belief that allowing it is inconsistent, useless, or both, but it is neither. C has a concept of incomplete types. It allows pointers to incomplete types, which is very important to the language, and it does not discriminate among incomplete types in this regard. C also makes no special-case rule against pointers to incomplete types being the types of function parameters.