Sukrit Akhauri
Sukrit Akhauri

Reputation: 41

Pointers with increment and decrement operators

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

Answers (4)

Aditya
Aditya

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

Keith Thompson
Keith Thompson

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

Lundin
Lundin

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:

  • The left operand of the assignment operators must always be a lvalue.
  • The result of the unary * 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.
  • The result of the ++ operators however, is not an lvalue, so it cannot be used as the left operand of assignment.

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

sepp2k
sepp2k

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

Related Questions