Certain declarations can use incomplete types, but others require complete object types. Those declarations that require object types are array elements, members of structures or unions, and objects local to a function. All other declarations permit incomplete types. In particular, the following constructs are permitted:
Pointers to incomplete types
Functions returning incomplete types
Incomplete function parameter types
typedef names for incomplete types
The function return and parameter types are special. Except for void, an incomplete type used in such a manner must be completed by the time the function is defined or called. A return type of void specifies a function that returns no value, and a single parameter type of void specifies a function that accepts no arguments.
Because array and function parameter types are rewritten to be pointer types, a seemingly incomplete array parameter type is not actually incomplete. The typical declaration of main’s argv, namely, char *argv[], as an unspecified length array of character pointers, is rewritten to be a pointer to character pointers.