Time for a brief update on the semantics of the array.
sizeof it is an operand of the sizeof or unary & operators or is a string literal that is used to initialize another array in the declaration, an expression of the type "N-element array of T " will be converted ("decay") to an expression of the type "pointer to T ", and the value of the expression will be the address of the first element in the array.
The expression array in your code is of type "2-element array char * " or char *[2] . When you pass it as an argument to func , as in
func( array, 2 );
the expression is converted to an expression of type "pointer to char * " or char ** , that is, the type that your function expects, and the value of the expression is the address of the first element: array == &array[0] . This is why you are not getting a warning for the second code snippet.
In the first fragment, the array is the operand of the unary operator & , therefore, conversion to the pointer type does not occur; instead, the type of the expression is a "pointer to a 2-element array char * " or char *(*)[2] , which is incompatible with char ** . The value of the address is the same (the address of the first element of the array matches the address of the array itself), but the types do not match, therefore, this is a warning.
So why does it matter? A pointer is just an address, and all addresses are the same, right? Well no. A pointer is an abstraction of an address, with corresponding type semantics. Pointers to different types should not have the same size or representation, and the arithmetic of a pointer depends on the type of the specified type.
For example, if I declare a pointer as char **p; , then the p++ expression will advance the pointer to point to the next object of type char * or sizeof (char *) bytes from the current address. However, if p declared as char *(*p)[2] , the p++ expression will advance p to point to the next two-element char * array, which is 2 * sizeof (char *) bytes from the current address.
John bode
source share