views:

153

answers:

4

Hi, I always thought that *&p = p = &*p in C. I tried this code:

 #include <stdio.h>
 #include <stdlib.h>

 char a[] = "programming";
 char *ap = &a[4];  

int main(void)
{

 printf("%x %x %x\n", ap, &*(ap), *&(ap));   /* line 13 */
 printf("%x %x %x\n\n", ap+1, &*(ap+1), *&(ap+1));   /* line 14 */
}

The first printf line (line 13) gives me the addresses:

40b0a8 40b0a8 40b0a8

which are the same as expected. But when I added the second printf line, Borland complains:

"first.c": E2027 Must take address of a memory location in function main at line 14

I was expecting to get:

40b0a9 40b0a9 40b0a9.

It seems that the expression *&(ap+1) on line 14 is the culprit here. I thought all three pointer expressions on line 14 are equivalent. Why am I thinking wrong?

A second related question: The line

char *ap = a;

points to the first element of array a. I used

char *ap = &a[4];  

to point to the 5th element of array a.

Is the expression

char *ap = a;

same as the expression

char *ap = &a[0];

Is the last expression only more verbose than the previous one?

Thanks a lot...

+6  A: 

You can only take the address of an lvalue, i.e. an expression that refers to an object. ap + 1 is an address calculation. It has a value but it's a temporary object so isn't an lvalue and you can't take its address.

In answer to your second question, in most contexts in expressions an array decays to a pointer to it's first element so yes, char *ap = a; and char *ap = &a[0]; are equivalent.

Charles Bailey
Thanks. I've heard about lvalues and rvalues. I'll need to study them.
yCalleecharan
A: 

If you believe one of those statements is the culprit specifically, I would break that line into three separate lines and see where the compiler complains at you. I bear the same suspicion, but to confirm it I would do just as I just told you to do.

eipxen
yCalleecharan
A: 

I believe Charles is correct about your main question, and you are correct about the second question: char *ap = a; is equivalent to char *ap = &a[0];.

sblair
Thanks. C is a tough but it's always fun to learn.
yCalleecharan
+1  A: 

When you use the C reference operator, it has to point to a valid lvalue, not an arbitrary expression. Thus, &(ap+1) isn't valid because the value ap+1 is simply an expression, not a location. You can't say ap+1 = foo();

And yes, a is the same as &a[0] here. Note that *(a+b) is 100% equivalent to a[b] (see the top answer to http://stackoverflow.com/questions/1995113/strangest-language-feature for an unusual example of this equivalence). When getting a pointer to a member of an array, you can use &array[i] or array + i. Example:

struct foo array[5];
struct foo *item_3 = &array[3];
struct foo *also_item_3 = array + 3;

In this case, whether to use array+i or &array[i] is a matter of style. &array[i] is arguably a better choice, as it is clearer that an array item is being gotten. Moreover, &vec[i] works with C++'s vectors, whereas vec+i does not.

Joey Adams
yCalleecharan
Joey Adams
Funny constructions/relationships. Thanks.
yCalleecharan
In case anyone does not know, lvalue means a value which can be assigned to, so can be on the Left side of the = operator
nategoose