By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,388 Members | 1,965 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,388 IT Pros & Developers. It's quick & easy.

array name and its address. Can they be same

P: n/a
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
su**************@yahoo.com

Nov 8 '06 #1
Share this Question
Share on Google+
20 Replies


P: n/a
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.
Nov 8 '06 #2

P: n/a
Richard Heathfield wrote:
>
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.

--
pete
Nov 8 '06 #3

P: n/a
pete said:
Richard Heathfield wrote:
>>
<snip>
>>
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.
Nov 8 '06 #4

P: n/a
Richard Heathfield <in*****@invalid.invalidwrites:
[...]
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>

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 8 '06 #5

P: n/a
Keith Thompson said:
Richard Heathfield <in*****@invalid.invalidwrites:
[...]
>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.
Nov 8 '06 #6

P: n/a
Richard Heathfield wrote:
Keith Thompson said:
Richard Heathfield <in*****@invalid.invalidwrites:
[...]
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.

--
Peter

Nov 8 '06 #7

P: n/a
Richard Heathfield <in*****@invalid.invalidwrites:
Keith Thompson said:
>Richard Heathfield <in*****@invalid.invalidwrites:
[...]
>>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.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 8 '06 #8

P: n/a
Keith Thompson said:
Richard Heathfield <in*****@invalid.invalidwrites:
>Keith Thompson said:
>>Richard Heathfield <in*****@invalid.invalidwrites:
[...]
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.
Nov 8 '06 #9

P: n/a
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>

--

Frederick Gotham
Nov 8 '06 #10

P: n/a
Richard Heathfield <in*****@invalid.invalidwrites:
Keith Thompson said:
[...]
>I was clarifying, not disagreeing.

Ah, I must have misunderstood "quibble". Thank you.
Only because I misused the word.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 8 '06 #11

P: n/a
Richard Heathfield wrote:
>
pete said:
Richard Heathfield wrote:
>
<snip>
>
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"?

--
pete
Nov 8 '06 #12

P: n/a
pete said:

<snip>
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.
Nov 8 '06 #13

P: n/a
Richard Heathfield <in*****@invalid.invalidwrites:
pete said:

<snip>
>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!)
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.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 8 '06 #14

P: n/a
Keith Thompson said:

<snip>
>
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.
Nov 9 '06 #15

P: n/a
Richard Heathfield <in*****@invalid.invalidwrites:
Keith Thompson said:

<snip>
>>
I think a (perhaps) more relevant question is:

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

ITYM void *p2 = &foo;
D'oh! (I fixed that in my test program, but forgot to copy the test
program into my newsreader.)
> 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.
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.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 9 '06 #16

P: n/a
Keith Thompson said:

<snip>
>
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.
Nov 9 '06 #17

P: n/a
Richard Heathfield <in*****@invalid.invalidwrites:
Keith Thompson said:

<snip>
>>
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

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 9 '06 #18

P: n/a
2006-11-09 <ln************@nuthaus.mib.org>,
Keith Thompson wrote:
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?
And yes, I'm being extraordinarily pedantic. (I
*hope* the OP has stopped reading by now.0
Nov 9 '06 #19

P: n/a
Jordan Abel wrote:
2006-11-09 <ln************@nuthaus.mib.org>,
Keith Thompson wrote:
>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.
>And yes, I'm being extraordinarily pedantic. (I
*hope* the OP has stopped reading by now.0
Agreed. We are arguing entirely theoretic points here which can be
interesting to some but confusing to those with less knowledge/experience.
--
Flash Gordon
Nov 9 '06 #20

P: n/a
In article <sl*******************@rlaptop.random.yi.org>,
Jordan Abel <ra*******@gmail.comwrote:
>char a[2][2]

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

Here is a useful (I think) way to think about the issues involved.
Imagine that pointers are not even fixed size (or, equivalently,
are fixed size but a megabyte each so that there is plenty of room
for the extra decoration I am about to describe).

Each pointer carries with it not only the "address of first byte
or word or whatever of object" but also "type of target object",
array dimensions if applicable, and/or offset within array if the
implementation feels like carrying such information.

Thus, some pointer value stored in some object p might contain the
actual literal (ASCII or EBCDIC or whatever) string:

"This pointer points to the third element of the array named
xyz in function glork() in stack frame #37. The array has type
`array 5 of pointer to array 2 of array 3 of pointer to function
(readonly pointer to char) returning void'."

(This is why "sizeof p" is one megabyte: that gives lots of room for
ASCII text. :-) )

In this implementation, comparisions for pointer equality first
simply (or complex-ly) checks whether they point to the same object
("array named <name>", "object named <name>", "malloc instance
#<number>"), and if the object is an array, have the same
element-number. If the types do not match, the comparison falls
back to locating the byte(s) to which the pointer points and seeing
if those are the same.

Dereferences (*p) first check whether the pointer points to an
actual, valid object, and if it is an array, whether the array offset
is within bounds, and so on.

Note that this implementation is able to reject attempts to use
a[0][3], even though the byte that would be addressed there exists.
By doing:

unsigned char *ucp = &a[0];

the implementation *does* allow accessing ucp[3], because the rules
for using a pointer of type "unsigned char *" that points into an
object explicitly allow accessing all the bytes of the object.
Converting the pointer back to "char (*)[2][2]", however, restores
the "correct" type, to which the subscript-limiting rules apply.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 9 '06 #21

This discussion thread is closed

Replies have been disabled for this discussion.