I had almost finished this when Keith's message showed up. There's a lot
of overlap between our messages, but I decided to post this one anyway,
because I take a slightly different tack to explaining the problems than
Keith did.
People,
Hope everyone's here's rocking.
I wrote a small code today, expecting something, but the result wasn't what I was expecting.
here's the code
void main()
{
int arr[] = {1,2,3,4};
int *p = NULL;
printf("\narr[0]: %x, &arr[0]: %x, &arr: %x, arr: %x", arr[0], &arr[0], &arr, arr);
The variable arguments of that call to printf() have the types 'int',
'int*', 'int (*)[4]', and 'int*', respectively.
p = arr;
printf("\np: %x, &p: %x", p, &p);
This time, the variable arguments have the types 'int*' and 'int**'.
The 'x' specifier requires that the corresponding argument be an
unsigned int. When one of printf()'s variable arguments has a promoted
type that doesn't match the corresponding format specifier, the behavior
(of your ENTIRE program) is undefined (7.21.6.1p9). That means that the
standard imposes no requirements on what your program will do. If you
had any expectations about what would happen when you executed your
program - any expectations at all, such as that it won't start playing
"The Star Spangled Banner" - those expectations were not justified by
anything it says in the C standard.
The C standard specifies only one format specifier for pointers, 'p'.
The corresponding arguments must be of type (void*). To print a pointer
of any other type, you need to cast it to void*.
'int' is required to have the same size and alignment as 'unsigned int',
and the same representation for positive 'int' values, so using '%x'
with arr[0] is a little more reasonable than using it for the pointers -
but it's still technically undefined behavior.
Whether or not the last character of a text stream must be an '\n' is
implementation-defined (7.21.2p2). Therefore, portable code should
always write a '\n' at the end of text streams.
}
EXAMPLE: ONe execution on my machine
arr[0]: 1, &arr[0]: bf8086cc, &arr: bf8086cc, arr: bf8086cc
p: bf8086cc, &p: bf8086dc
On executing this, as you probably know, all prints except the last one (&p) are same.
Rest looks ok, how come &arr and arr are same here?
Despite what I said above, on many implementations your code will
actually work. The results that you actually got imply that, under the
implementation of C that you're using, all of the different pointer
types that you've tried to print out had exactly the same size as
unsigned int. The standard allows incompatible pointer types to have
different sizes, though it's quite common for all of them to be same.
Even if they're all the same size, it's not guaranteed to be the same as
the size of unsigned int. You just got unlucky - the defect in your code
happened to have no ill effects, so you lost an opportunity to realize
that it was defective.
In most contexts, an lvalue of array type, such as 'arr', is
automatically converted into a pointer to the first element of the
array. One of the three exceptions to that rule is when it is an
argument of the & operator. That's why &arr has the type int(*)[4],
while arr has the type int*. &arr points at the start of 'arr', while
arr points at the start of a[0]. Since a[0] is the very first element of
arr, both pointers point at the same location in memory, which is why
they printed out the same.