Is there a way to write something like below:
int i = 0;
int *p1 = &(i );
int *p2 = &( i);
CodePudding user response:
Before asking "Is there a way", I think we have to ask, "What would it mean?"
In C, we have the concept of "object" versus "value". Basically, an object is a thing that can hold a value. So a variable like
int a;
is clearly an object, because it can hold a value — that is, we can say things like
a = 5;
to store a value into a
.
The key distinction between an object and a value is that an object has a location. A value, on the other hand, is something we've computed that's just kind of floating in space, and if we don't find an object to store it in pretty soon, it disappears.
(Side note: You will sometimes come across the terms "lvalue" and "rvalue", which mean the same thing as "object" and "value" as I've been using them here. An lvalue is something that can appear on the left side of an assignment operator, while an rvalue is something that can only appear on the right.)
I've gone through this longish background introduction just so I can make this important point: You can only apply the address-of operator to an object, because only objects have locations. It makes perfect sense to say
int *p = &a;
But it would make no sense to say
int *p2 = &5; /* WRONG */
or
int *p3 = &(1 2); /* WRONG */
So it would equally make no sense to write
int *p4 = &(a 1); /* WRONG */
The variable a
is an object, but the thing that you get by fetching a
's value and adding 1 to it is clearly just a value. By the time we've computed that value, it doesn't really matter (we might as well have forgotten) that one part of the computation of that value involved fetching a value from the object a
.
But then we get you your questions. Suppose you try to write
int *p5 = &(i ); /* questionable */
int *p6 = &( i);
The
operator takes a value and adds 1 to it, and the value i 1
is clearly just a value, without a location. But, its true, i
and i
mean more than just "i 1
" — they compute the value i 1
and store it back into i
. So you can almost convince yourself that i
and i
have locations — but if they did, it would just be the location of the variable i
. So you might as well have just said
int *p7 = &i;
Now, you might ask, "But what if I want to take the address of i
, at the same time I increment it?" And the answer is, you're just going to have to do it in two steps:
int *p7 = &i;
i ;
Yes, it's true, the i
and i
operators are nice in that they let you do two things at once, things like
int x = array[i ];
or
int x = *p ;
But those are useful operations, because they come up all the time when you're working with arrays. But the need to say something like
int *p5 = &(i );
comes up much less often, I think, so it's not nearly so important to have it work. (Me, I've been programming in C for 40 years, and I don't think I've ever felt the need to grab a pointer to i
and increment it at the same time.) The
operator is something that often comes up in a loop, as i
moves through an array or something. But since the address of i
doesn't change, if you need a pointer to it, It makes sense to do that just once, before the loop (or whatever) even starts.
Finally, whether you agree with my explanations so far or not, the C Standard explicitly says that the result of the
and --
operators is an rvalue, not an lvalue. Two compilers I just tried this on gave me the errors
error: cannot take the address of an rvalue of type 'int'
and
error: lvalue required as unary ‘&’ operand
and these error messages pretty much say the same story I've been telling.
Although, to throw a pretty big monkey wrench into this story I've been telling, the rules are evidently different in C ! You can't do &(i )
, but you can do &( i)
! I think there's a good reason for this, but I don't remember what it is.
CodePudding user response:
In C , The statement
int *p1 = &(i );
will not work as i
returns an rvalue and you cannot take the address of an rvalue
.
On the other hand the statement
int *p2 = &( i);
is fine(i.e., it works). Check it out here
CodePudding user response:
i
yields the value of i
before being incremented and increments it.
If &(i )
were valid, it would mean take the address of the "previous value". Since i
is the name we are using for a single memory location, where would that previous value go?
If you need the previous value of i
, it needs to be stored somewhere before you can do anything with it including pointing to it.
int j = i ;
int *ip = &i;
int *jp = &j;
Then, *ip
will yield the incremented value and *jp
will yield the value before the increment.
Since i
yields the incremented value of i
, it works with just a single value. Still, for clarity, best to use separate statements for the increment and taking the address of the variable:
int *ip = &i;
i;
even if the compiler allows &( i)
or even if it is legal (did not check). You are writing for the fellow programmer (who might be you), not the compiler.