Array[0] vs Pointer

V

Varun Tewari

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);

p = arr;
printf("\np: %x, &p: %x", p, &p);
}

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?
 
K

Keith Thompson

Varun Tewari said:
I wrote a small code today, expecting something, but the result wasn't what I was expecting.

here's the code

void main()

"void main" is very useful, mostly as a way of detecting C books and
tutorials written by someone who doesn't really know the language. "int
main(void)" would be correct.
{
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);

You need a "#include <stdio.h>" at the top of your program.

The "\n" should be at the end of the output line not at the beginning.

The correct format to print a pointer value is "%p", not "%x", and it
expects a void* argument, so a pointer of another type should be
converted via a cast. "%x" is likely to work *if* unsigned int is the
same size as a pointer, but it's risky and incorrect.

Using "%x" for an int is ok (as long as it's non-negative), but it's
really for unsigned int; unless you really need hexadecimal output (and
for the value 1 it doesn't matter), just use "%d". (A special-case rule
says that int and unsigned int are interchangeable as function arguments
as long as the value is within the range of both types, which it is in
this case.)
p = arr;
printf("\np: %x, &p: %x", p, &p);
}

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?

Here's a corrected version of you program:

#include <stdio.h>
int main(void)
{
int arr[] = {1,2,3,4};
int *p = NULL;

printf("arr[0]: %d, &arr[0]: %p, &arr: %p, arr: %p\n",
arr[0], (void*)&arr[0], (void*)&arr, (void*)arr);

p = arr;
printf("p: %p, &p: %p\n", (void*)p, (void*)&p);
return 0;
}

and the output I get on my system:

arr[0]: 1, &arr[0]: 0xbfbfd9c0, &arr: 0xbfbfd9c0, arr: 0xbfbfd9c0
p: 0xbfbfd9c0, &p: 0xbfbfd9bc

Quick answer: An array expression is, in most but not all contexts,
implicitly converted to a pointer to the array's first element. The
expression `arr` is converted to a pointer to `arr[0]`. `&arr` is the
address of the whole array; it's the same memory address, but has a
different type (pointer to array vs. pointer to int).

The relationship between arrays and pointers in C is tricky and often
counterintuitive. Section 6 of the comp.lang.c FAQ,
<http://www.c-faq.com/>, explains it better than I have time to here.
Read it and come back if you stil have questions.
 
J

James Kuyper

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.
 
V

Varun Tewari

@Keith,@James,

Sorry guys, I forgot to mention that sizoe(int) = sizeof(unsigned int) = sizeof(void *) = 4 on my machine.
Yes, I indeed missed the %p aspect in the real code too. Thnx for pointing this.
 
L

Les Cargill

Varun said:
@Keith,@James,

Sorry guys, I forgot to mention that sizoe(int) = sizeof(unsigned int) = sizeof(void *) = 4 on my machine.
Yes, I indeed missed the %p aspect in the real code too. Thnx for pointing this.

If you use %x or %lx instead of %p, chances are it'll be fine. Since
that sort of thing is very nearly always used in debug prints, it's less
sinful. :) when else do you need to serialize pointers?
 
J

James Kuyper

If you use %x or %lx instead of %p, chances are it'll be fine. ...

Why use anything other than the correct specifier? It might work, but
it's pretty unlikely to do so on any machine where sizeof(unsigned int)
!= sizeof(void*).
... Since
that sort of thing is very nearly always used in debug prints, it's less
sinful. :) when else do you need to serialize pointers?

If it ever goes wrong, which it could, you could end up wasting a lot
more time trying to figure out why, than you would have spent simply
typing in the correct format specifier. The last thing you need when
you're debugging a problem is to be distracted by such issues.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top