[Given "int arr[N];" and considering "&arr" vs "&arr[0]")
Everything else you've said is spot on, but this is slightly incorrect.
Actually, it is completely correct.
But it does not tell you
all that much by itself: as I have shown before, the values of
3 and 3.14 are identical too:
int i = 3;
double d = 3.14;
if ((char)i == (char)d)
puts("3 and 3.14 are identical");
else
puts("3 and 3.14 are different");
Obviously they are only "identical" after conversion to a common
type -- in this case "char" -- and the results may (and do) change
if we pick a different common type:
if ((float)i == (float)d)
puts("3 and 3.14 are identical");
else
puts("3 and 3.14 are different");
To compare &arr against &arr[0], we have to convert to a common
type; and as with the int/double arrangement above, this may change
the value(s) in the process:
#include <stdio.h>
int glob_array[5];
int main(void)
{
int fn_array[5];
if ((&glob_array != glob_array) || (&fn_array != fn_array))
printf("I haven't seen a situation like this before.\n");
}
If you actually compile this, you get the required diagnostic,
and in this particular case, two more diagnostics:
% cc -O2 -W -Wall -ansi -pedantic -o t t.c
t.c: In function `main':
t.c:8: warning: comparison of distinct pointer types lacks a cast
t.c:8: warning: comparison of distinct pointer types lacks a cast
t.c:10: warning: control reaches end of non-void function
(the C standard requires only that "at least one diagnostic" come
out, and does not say whether it is a "warning", or an "error", or
even a "kumquat"). We can fix this by inserting a conversion to
some common type: for instance, we could cast both to "char *".
But introducing a conversion gets us back to that 3==3.14 problem.
I think the real question boils down to whether &arr and &arr[0]
will compare equal under *all* "well-defined" conversions -- which
may even be only those to "char *" and "void *" -- and then I think
the answer is "yes", so that we can in fact say that the converted
values are always identical as long as we do a sensible conversion.
But, onward:
However in the context of a function parameter, it is not true. Given
that in C parameters are passed by value, it's not possible for the
address of the array parameter to equal the address of the original array
and therefore it's not possible for the address of the array parameter to
equal the address of the first element that it points to. i.e. we can
write:
#include <stdio.h>
void somefunction(int arrayparm[5])
{
if (arrayparm == &arrayparm)
printf("Something impossible has occurred.\n");
}
The real problem here is "what you see, well, all of it's a lie"[%].
The variable named "arrayparm" has type "pointer to int", not "array
5 of int". We can expose the lie via various operators:
/* these sizes will differ (unless you get VERY unlucky) */
printf("sizeof (int [5]) = %lu\n", (unsigned long)sizeof (int [5]));
printf("sizeof arrayparm = %lu\n", (unsigned long)sizeof arrayparm);
/* cannot do this with an array */
arrayparm = NULL;
and of course, your own example, once we insert some appropriate
conversions to eliminate the need for a diagnostic (and perhaps no
executable program as a consequence of the diagnostic):
printf("%p != %p, we presume\n", (void *)arrayparm, (void *)&arrayparm);
if ((void *)arrayparm != (void *)&arrayparm)
puts("we presumed correctly");
else
puts("uh oh");
[% "Wine from the Water", from Try Anything Once]