Reputation: 41
In general, when the assignment operator is there left operand should be a variable and not an expression but when I am making left side an expression using pointers, the code is not producing any error.
Jdoodle online compiler/C
It should throw an error however successful compilation is there.
https://www.jdoodle.com/c-online-compiler
#include <stdio.h>
int main()
{
int x = 30, *y, *z;
y = &x; // Assume address of x is 1000 and integer is 4 byte size */
z = y;
*y++ = *z++;
x++;
return 0;
}
Upvotes: 3
Views: 314
Reputation: 56
Suppose, address of x
is 1000
and sizeof(int) = 4
(for a 32-bit
compiler), then when you evaluate the expression:
*y++=*z++;
Address of z is incremented
(Since, post-increment(x++) has higher precedence than ( *x ) )
but before that rvalue i.e. address stored by z
is assigned to pointer y
.
After that only increment of address and dereferencing is taking place.
Similar is the case for *y++
, first address is assigned, post-increment occurs and is then dereferenced. If you are confused about lvalue to be a variable, it is not necessary E.g. : adding a statement like in your code after initializing the pointer with a valid address
*y++;
is also correct and will not flag any error.
Upvotes: 1
Reputation: 263617
In general, when the assignment operator is there left operand should be a variable and not an expression ...
The left operand of an assignment operator is always an expression. The restriction is that it has to be an lvalue, which is (simplifying a bit) an expression that designates an object.
The simplest case of an lvalue is the name of a declared object/variable, so for example:
int n;
n = 42;
n
is an expression, specifically an lvalue, that designates the object named n
.
In your example, you have:
*y++ = *z++;
Operator precedence says that the ++
operator binds more tightly than the *
operator, so this is equivalent to:
*(y++) = *(z++);
y++
and z++
are not values -- they're expressions that yield pointer values, but they don't designate any objects. But the unary *
operator gives you an lvalue even when its operand is not an lvalue. y++
yields a pointer value, and *(y++)
gives you the object that that pointer points to.
The C standard doesn't use the term "variable" in this sense. It talks about objects, which may or may not be declared objects with simple names. an_object
, *pointer_value
, array[index]
, and structure_object.member
all refer to objects and can appear on the left side of an assignment.
Upvotes: 2
Reputation: 214890
left operand should be a variable and not an expression
This is a misunderstanding. The term you are looking for is lvalue. This a C standard gibberish term originating from the term "left value". The definition of the term lvalue is roughly: an expression that designates an object.
The rules for the various operators discussed here are:
*
operator is defined to always be a lvalue, so you can use it as if it was an object, and we can assign to it. Examples:
int x; int* y;
x = 5; // Here x is both an object and an lvalue, so the code is valid
y = &x; // y is both a (pointer) object and an lvalue, code is valid.
*y = 0; // *y is an lvalue designating the object y, code is valid
y++ = 1; // y++ is not an lvalue, the code is invalid
As for why *y++
works, it is just a matter of operator precedence. The ++ is applied first, but since it is postfix, the change doesn't take place until the end of the expression. So *
is applied to y
and the result is a lvalue.
Had you written ++*y = 0;
then operator associativity had caused the *
to execute first, the result *y
being an lvalue. And then when you use ++
on that lvalue, the result of ++ is not an lvalue so the code is invalid. ++*y
in itself is valid code, but it can't be the left operand of assignment.
Upvotes: 2
Reputation: 370425
The left operand of an assignment does not have to be a variable. For example, the following assignments should and do work perfectly fine (and I assume you know that and just misspoke):
array[index] = value;
*ptr = value;
I think what's confusing you about *y++ = *z++;
is that you think that it's assigning to the result of an increment operation, which would indeed make no sense. But that's not the precedence of that expression: *y++
is equivalent to *(y++)
, not (*y)++
. So you're dereferencing the result of y++
and then assign a value to that dereferenced memory location, just as if you had written:
int *ptr = y++;
*ptr = *z++;
Upvotes: 2