array name and its address. Can they be same

S

subramanian

Hello
I have a doubt in the following piece of code:

int a[10];
printf("a=%p\n", a);
printf("&a=%p\n", &a);

these printf statements print the same value for both 'a' and '&a".
I tried in VC++version 6 and also Redhat Enterprise Linux 4.
Should' t these memory locations be different?
What is the reason for this behaviour

Thanks
(e-mail address removed)
 
R

Richard Heathfield

subramanian said:
Hello
I have a doubt in the following piece of code:

int a[10];
printf("a=%p\n", a);
printf("&a=%p\n", &a);

If you supply a pointer of a type other than void * to printf as a match for
its %p specifier, the behaviour of the program is undefined.
these printf statements print the same value for both 'a' and '&a".

a is an array of 10 int. When used in a value context, the expression decays
into a pointer to the first element in that array. That is, it is
equivalent to &a[0].

&a is a pointer to an array of 10 int. It has a different type to a.
Incidentally, a is an appalling choice of name in example code.
I tried in VC++version 6 and also Redhat Enterprise Linux 4.
Should' t these memory locations be different?
Why?

What is the reason for this behaviour

The behaviour is undefined. Nevertheless, the following program is highly
likely to produce equivalent results:

#include <stdio.h>

int main(void)
{
int foo[10];
printf("foo=%p\n", (void *)foo);
printf("&foo=%p\n", (void *)&foo);
return 0;
}

The reason this program is likely to print the same pointer value for foo
and &foo is that an array is an aggregate object in which there is no
padding, and therefore the array comprises (in this case) ten member
objects that fit into it exactly:

+--------+--------+--------+--------+--------+--------+ ...
| foo[0] | foo[1] | foo[2] | foo[3] | foo[4] | foo[5] | ...
+--------+--------+--------+--------+--------+--------+--...
| foo ...
+--------+--------+--------+--------+--------+--------+--...

As you can see, both foo[0] and foo share a common beginning point. So they
are both at the same address. Nevertheless, they are still of different
types.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not
adjust your email clients.
 
P

pete

Richard said:
subramanian said:
Hello
I have a doubt in the following piece of code:

int a[10];
printf("a=%p\n", a);
printf("&a=%p\n", &a);

If you supply a pointer of a type other than void * to printf as a match for
its %p specifier, the behaviour of the program is undefined.
these printf statements print the same value for both 'a' and '&a".

a is an array of 10 int. When used in a value context, the expression decays
into a pointer to the first element in that array. That is, it is
equivalent to &a[0].

&a is a pointer to an array of 10 int. It has a different type to a.
Incidentally, a is an appalling choice of name in example code.
I tried in VC++version 6 and also Redhat Enterprise Linux 4.
Should' t these memory locations be different?
Why?

What is the reason for this behaviour

The behaviour is undefined.
Nevertheless, the following program is highly
likely to produce equivalent results:

#include <stdio.h>

int main(void)
{
int foo[10];
printf("foo=%p\n", (void *)foo);
printf("&foo=%p\n", (void *)&foo);
return 0;
}

The reason this program is likely
to print the same pointer value for foo
and &foo is that an array is an aggregate object in which there is no
padding, and therefore the array comprises (in this case) ten member
objects that fit into it exactly:

+--------+--------+--------+--------+--------+--------+ ...
| foo[0] | foo[1] | foo[2] | foo[3] | foo[4] | foo[5] | ...
+--------+--------+--------+--------+--------+--------+--...
| foo ...
+--------+--------+--------+--------+--------+--------+--...

As you can see, both foo[0] and foo share a common beginning point.
So they are both at the same address.
Nevertheless, they are still of different types.

((char *)&foo) is equal to ((char *)foo), and
(char *) and (void *) have the same representation,
so I don't think that the different types, makes a difference.
 
R

Richard Heathfield

pete said:
As you can see, both foo[0] and foo share a common beginning point.
So they are both at the same address.
Nevertheless, they are still of different types.

((char *)&foo) is equal to ((char *)foo), and
(char *) and (void *) have the same representation,
so I don't think that the different types, makes a difference.

Not to their address, no. I made that clear enough, did I not? What I was
trying to ensure was that the OP did not go away thinking foo and &foo are
interchangeable, fungible, or possessed of identical semantics.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not
adjust your email clients.
 
K

Keith Thompson

Richard Heathfield said:
a is an array of 10 int. When used in a value context, the expression decays
into a pointer to the first element in that array. That is, it is
equivalent to &a[0].

<quibble>
It decays when used in a context other than as the operand of a unary
"&" or "sizeof" operator, (That's probably what you meant by "value
context".)
</quibble>
 
R

Richard Heathfield

Keith Thompson said:
Richard Heathfield said:
a is an array of 10 int. When used in a value context, the expression
decays into a pointer to the first element in that array. That is, it is
equivalent to &a[0].

<quibble>
It decays when used in a context other than as the operand of a unary
"&" or "sizeof" operator, (That's probably what you meant by "value
context".)

Yes - it decays when you take its value. Do you know of some other context
in which it decays, which renders my summary inaccurate?

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not
adjust your email clients.
 
P

Peter Nilsson

Richard said:
Keith Thompson said:
Richard Heathfield said:
a is an array of 10 int. When used in a value context, the expression
decays into a pointer to the first element in that array. That is, it is
equivalent to &a[0].

<quibble>
It decays when used in a context other than as the operand of a unary
"&" or "sizeof" operator, (That's probably what you meant by "value
context".)

Yes - it decays when you take its value.

[Debatable in the case of variable-length arrays.]
Do you know of some other context
in which it decays, which renders my summary inaccurate?

I think Keith was talking about when it doesn't decay. I don't think
"used in a
value context" is as intuitively obvious as it might sound to you. In
cases like
&*p, the *p is a value as much as anything else.
 
K

Keith Thompson

Richard Heathfield said:
Keith Thompson said:
Richard Heathfield said:
a is an array of 10 int. When used in a value context, the expression
decays into a pointer to the first element in that array. That is, it is
equivalent to &a[0].

<quibble>
It decays when used in a context other than as the operand of a unary
"&" or "sizeof" operator, (That's probably what you meant by "value
context".)

Yes - it decays when you take its value. Do you know of some other context
in which it decays, which renders my summary inaccurate?

I was clarifying, not disagreeing. I wasn't certain what "value
context" meant; I thought others might be confused as well.
 
R

Richard Heathfield

Keith Thompson said:
Richard Heathfield said:
Keith Thompson said:
[...]
a is an array of 10 int. When used in a value context, the expression
decays into a pointer to the first element in that array. That is, it
is equivalent to &a[0].

<quibble>
It decays when used in a context other than as the operand of a unary
"&" or "sizeof" operator, (That's probably what you meant by "value
context".)

Yes - it decays when you take its value. Do you know of some other
context in which it decays, which renders my summary inaccurate?

I was clarifying, not disagreeing.

Ah, I must have misunderstood "quibble". Thank you.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not
adjust your email clients.
 
F

Frederick Gotham

Keith Thompson:
<quibble>
It decays when used in a context other than as the operand of a unary
"&" or "sizeof" operator, (That's probably what you meant by "value
context".)
</quibble>


I'll give my own understanding of it (which is sound for both C and C++).

First thing:

A conversion won't occur unless it needs to occur.

For intance, in the following, there's no need for a conversion, as an int
can be assigned directly to an int:

int a=0,b;

b = a;

Here's an example however of a place where a conversion need take place:

int a=0; double b;

b = a;

The thing to remember is that if there's no need for a conversion, there
won't be a conversion.

Here's an example of where there's no need for a conversion:

int arr[15];

sizeof arr;

The array type won't implicitly convert to a pointer to its first element,
and that's because sizeof can work with any type, thus relieving the need
for a conversion to a pointer to the first element. So once again, a
conversion doesn't take place unless it needs to take place.

Here though, is an example of where a conversion need take place:

int *p = arr;

Just as how a double can implicitly convert to an int, an array can
implicitly convert to a pointer to its first element.

One thing to note though, is that none of the following operators work on
arrays:

+ (addition)
- (subtraction)
* (dereference)
[] (subscript)

All of these operators work with pointers rather than arrays. Therefore, if
you try to use them on an array, then you necessitate an implicit
conversion to a pointer to the first element.

My own understanding of "conversion won't take place unless it has to"
works well for me, because it satisfies my needs both as a C programmer and
as a C++ programmer.

In C, I believe you can count on one hand the places where an array can
actually stay as an array, so such a verbose explanation as this isn't
necessary. However, in C++, it's more complicated on account of references,
function overloading, templates, etc..

<OFF-TOPIC>
I realise this is horribly off-topic, but just to satisfy anyone's
curiosity, here's an example of where this understanding would work well in
C++. Here are two overloads of the same function:

void Func(int *p) {}

void Func(int (&arr)[10]) {}

The first overload takes a pointer, while the second takes a reference to
an array of 10 int's. If we were to invoke "Func" in code such as the
following:

int main()
{
int arr[10];

Func(arr);
}

, then we know which overload will be invoked because we know that a
conversion will only take place when it needs to take place. In this
particular case, there's no need for the implicit conversion to a pointer
to the first element, as the array object itself can be used.
</OFF-TOPIC>
 
P

pete

Richard said:
pete said:
As you can see, both foo[0] and foo share a common beginning point.
So they are both at the same address.
Nevertheless, they are still of different types.

((char *)&foo) is equal to ((char *)foo), and
(char *) and (void *) have the same representation,
so I don't think that the different types, makes a difference.

Not to their address, no. I made that clear enough, did I not?

Regarding:
printf("foo=%p\n", (void *)foo);
printf("&foo=%p\n", (void *)&foo);
you said
"The reason this program is likely to print
the same pointer value for foo and &foo..."
Is it merely "likely"?
 
R

Richard Heathfield

pete said:

Regarding:
printf("foo=%p\n", (void *)foo);
printf("&foo=%p\n", (void *)&foo);
you said
"The reason this program is likely to print
the same pointer value for foo and &foo..."
Is it merely "likely"?

Yes, it's merely likely. For example, on MS-DOS, it would be perfectly legal
for the output to be:

foo=0900:8000
&foo=0CB7:4490

(It would also, however, be reasonable for you to argue that these are the
same value!)

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not
adjust your email clients.
 
K

Keith Thompson

Richard Heathfield said:
pete said:



Yes, it's merely likely. For example, on MS-DOS, it would be perfectly legal
for the output to be:

foo=0900:8000
&foo=0CB7:4490

(It would also, however, be reasonable for you to argue that these are the
same value!)

I think a (perhaps) more relevant question is:

void *p1 = foo; /* cast is unnecessary */
void *p2 = *foo;
if (p1 == p2) {
puts("equal");
}
else {
puts("not equal");
}

Can this ever print "not equal"?

I believe it must always print "equal", but in an overly quick look in
the standard I haven't found proof.
 
R

Richard Heathfield

Keith Thompson said:

I think a (perhaps) more relevant question is:

void *p1 = foo; /* cast is unnecessary */
void *p2 = *foo;

ITYM void *p2 = &foo;
if (p1 == p2) {
puts("equal");
}
else {
puts("not equal");
}

Can this ever print "not equal"?

I believe it must always print "equal",

I think so, too, because the implementation is not allowed to insert padding
before the first element in the array.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not
adjust your email clients.
 
K

Keith Thompson

Richard Heathfield said:
Keith Thompson said:



ITYM void *p2 = &foo;

D'oh! (I fixed that in my test program, but forgot to copy the test
program into my newsreader.)
I think so, too, because the implementation is not allowed to insert padding
before the first element in the array.

Ah, here it is, C99 6.5.9p6 (describing equality operators):

Two pointers compare equal if and only if both are null pointers,
both are pointers to the same object (including a pointer to an
object and a subobject at its beginning) or function, both are
pointers to one past the last element of the same array object, or
one is a pointer to one past the end of one array object and the
other is a pointer to the start of a different array object that
happens to immediately follow the first array object in the
address space.

Combined with the sematics of pointer conversion in 6.3.2.3, I don't
see how the program can print "not equal". At the very least, I'd be
very impressed by the sheer useless perverse ingenuity of any
implementation that managed to have this program print "not equal"
without violating the letter of the standard.
 
R

Richard Heathfield

Keith Thompson said:

Ah, here it is, C99 6.5.9p6 (describing equality operators):

Two pointers compare equal if and only if both are null pointers,
both are pointers to the same object (including a pointer to an
object and a subobject at its beginning) or function, both are
pointers to one past the last element of the same array object, or
one is a pointer to one past the end of one array object and the
other is a pointer to the start of a different array object that
happens to immediately follow the first array object in the
address space.

Combined with the sema[n]tics of pointer conversion in 6.3.2.3, I don't
see how the program can print "not equal".

The wording "if and only if...both are pointers to the same object
(including a pointer to an object and a subobject at its beginning)..."
means that it can't.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not
adjust your email clients.
 
K

Keith Thompson

Richard Heathfield said:
Keith Thompson said:

Ah, here it is, C99 6.5.9p6 (describing equality operators):

Two pointers compare equal if and only if both are null pointers,
both are pointers to the same object (including a pointer to an
object and a subobject at its beginning) or function, both are
pointers to one past the last element of the same array object, or
one is a pointer to one past the end of one array object and the
other is a pointer to the start of a different array object that
happens to immediately follow the first array object in the
address space.

Combined with the sema[n]tics of pointer conversion in 6.3.2.3, I don't
see how the program can print "not equal".

The wording "if and only if...both are pointers to the same object
(including a pointer to an object and a subobject at its beginning)..."
means that it can't.

The piece I haven't yet found is a guarantee that if I take a pointer
to an object and convert it to void*, it's still a pointer to the same
object. C99 6.3.2.3p7, describing pointer conversions, talks about
converting from one pointer type to another and back again, but it
leaves open the possibility that a conversion from int* to void* could
behave differently than a conversion from int(*)[10] to void*.

But I'm probably just not finding the section that makes this obvious.
If this weren't guaranteed, then memcpy(), memmove(), and memcpy()
wouldn't work. And yes, I'm being extraordinarily pedantic. (I
*hope* the OP has stopped reading by now.0
 
J

Jordan Abel

2006-11-09 said:
The piece I haven't yet found is a guarantee that if I take a pointer
to an object and convert it to void*, it's still a pointer to the same
object. C99 6.3.2.3p7, describing pointer conversions, talks about
converting from one pointer type to another and back again, but it
leaves open the possibility that a conversion from int* to void* could
behave differently than a conversion from int(*)[10] to void*.

I think we determined in the thread about arrays of arrays and overrun
and indexing that there's not such a guarantee - a pointer can contain
information about the size of the memory area it points into.
But I'm probably just not finding the section that makes this obvious.
If this weren't guaranteed, then memcpy(), memmove(), and memcpy()
wouldn't work.

Not necessarily.

char a[2][2]

(void*)(a[0]) points to the first of two bytes.
(void*)(a) points to the first of four bytes.

Or am I misunderstanding the question?
 
F

Flash Gordon

Jordan said:
2006-11-09 said:
The piece I haven't yet found is a guarantee that if I take a pointer
to an object and convert it to void*, it's still a pointer to the same
object. C99 6.3.2.3p7, describing pointer conversions, talks about
converting from one pointer type to another and back again, but it
leaves open the possibility that a conversion from int* to void* could
behave differently than a conversion from int(*)[10] to void*.

I think we determined in the thread about arrays of arrays and overrun
and indexing that there's not such a guarantee - a pointer can contain
information about the size of the memory area it points into.

Here are some points to consider...

C99 6.3.2.3p7 Converted to a pointer to char it is required to be a
pointer to the lowest addressed byte of an object. Obviously this byte
is the same whichever type it came from.

C99 6.2.5p26 void* and char* are required to be the same size and have
the same representation.

So after the conversion both pointers have representations of pointers
to the same char.

So if you converted the pointers to pointers to char they would be
required to compare equal even if they had different representations
(say additional bits saying what the original object type was).

Now, as pointers to void is it allowed to do a simple bitwise comparison
of the two pointers (and so show them as different) or is the comparison
required to produce the same result as if you converted them to pointers
to char first?

I would say that a valid argument is that the pointer point to the same
byte, therefore even as incomplete object types they point to the same
(incomplete) object, so they must compare equal. I'm sure this was the
intent.

However, I can also see that a sufficiently perverse implementer could
argue that they don't point to objects, only incomplete objects, so they
are allowed to compare different.
But I'm probably just not finding the section that makes this obvious.
If this weren't guaranteed, then memcpy(), memmove(), and memcpy()
wouldn't work.

Not necessarily.

char a[2][2]

(void*)(a[0]) points to the first of two bytes.
(void*)(a) points to the first of four bytes.

Or am I misunderstanding the question?

I agree that memcpy et al would be required to work since the void
pointers point to the same byte and these functions are required to
treat the bytes as unsigned char.

Agreed. We are arguing entirely theoretic points here which can be
interesting to some but confusing to those with less knowledge/experience.
 

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,781
Messages
2,569,615
Members
45,294
Latest member
LandonPigo

Latest Threads

Top