-1

According to "C - A Reference Manual", an lvalue is an expression that refers to an object in such a way that the object may be examined or altered.

For example,

int ranks[10];

Then are ranks and ranks+3 lvalues? Since ranks(pointer to first element of array) and ranks+3(pointer to fourth element of array) refer to objects, I guess they are lvalues -- or are they not lvalues?

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
Jin
  • 1,902
  • 3
  • 15
  • 26
  • Possible duplicate of [C How to identify rvalue and lvalue?](http://stackoverflow.com/questions/11105284/c-how-to-identify-rvalue-and-lvalue) – underscore_d Aug 17 '16 at 15:53
  • 1
    C11 draft standard n1570, *6.3 Conversions 6.3.2.1 Lvalues, arrays, and function designators 3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.* – EOF Aug 17 '16 at 15:54
  • It depends on the context. Please provide that context. – 2501 Aug 17 '16 at 16:12
  • @chux: I fixed the typo. – Keith Thompson Aug 17 '16 at 16:25
  • 1
    `ranks+3` is definitely not an lvalue. `ranks` is an lvalue in the context of `sizeof ranks` or `&ranks` (in those cases it refers to the entire array object, not to the address of its initial element). It is not an lvalue in other contexts. – Keith Thompson Aug 17 '16 at 16:27
  • @KeithThompson So pointers cannot be lvalues except for special cases? But doesn't address of memory refer to object just like identifiers refer to objects? So I still think that pointers can be called lvalues! – Jin Aug 17 '16 at 16:52
  • @Jin: a pointer *value* cannot be an lvalue; you must dereference that pointer *value* with either the unary `*` or subscript `[]` operators to manipulate the contents of that memory address. – John Bode Aug 17 '16 at 17:12
  • 2
    @Jin: An lvalue is a kind of expression, not a kind of value, defined by the C11 standard as "an expression (with an object type other than void) that potentially designates an object". An expression of pointer type can certainly be an lvalue if it designates an object of pointer type. I recommend using the word "pointer" as an adjective, not as a noun. We can have pointer values, pointer objects, pointer types, pointer expressions, and so forth. The phrase "a pointer" can be ambiguous. – Keith Thompson Aug 17 '16 at 18:11
  • @JohnBode @KeithThompson : Isn't `ranks` a pointer type expression, not a kind of value? – Jin Aug 18 '16 at 00:27

2 Answers2

3

ranks+3 is not an lvalue for the same reason that 1+3 is not an lvalue; the result is simply a numerical (pointer) value, not a reference to an object.

Put another way, if the result of ranks + 3 is 0xdeadbeef, you cannot write

0xdeadbeef = 10;

for the same reason you cannot write

4 = 10;

However, *(ranks+3) is an lvalue, because you are dereferencing that pointer value; it is the 4th element of the ranks array, and is equivalent to ranks[3].

Similarly, ranks is not an lvalue except in the context of sizeof or the unary & operator. Since array expressions "decay" to pointer expressions in most contexts, you again wind up with the situation of

ranks = 10;

being equivalent to

0xdeadbeef = 10;  

Again, you'd have to dereference ranks as either *ranks or ranks[0] for it to be an lvalue.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • If I add `int x = 10' and `x=0' to my code and apply your logic, since x is an int expression then `x=0`would be equivalent to `10=0'..? – Jin Aug 18 '16 at 00:16
  • Why doesn't your logic apply to int expression? I think the difference originates from fact that the compiler simply evaluates `ranks` as `0xdeadbeef` while the compiler doesn't evaluate `x` as `10`? – Jin Aug 18 '16 at 01:47
2

In this context, the names aren't lvalues, but they can be dereferenced with * to form lvalues. For example:

int ranks[10];
// ranks = 42; <--- doesn't compile!   error: assignment to expression with array type
*ranks = 42;   // OK: same as ranks[0] = 42
//ranks+3 = 42; <--- error: lvalue required as left operand of assignment
*(ranks+3) = 42; //OK: same as ranks[3] = 42

This answer lists the few cases in C when the name of an array doesn't decay to a pointer to the array's first element. On the left-hand side of an assignment isn't one of those cases. Therefore, in ranks = ..., ranks is (decays to, acts as) a pointer to the first element of the array. You have to dereference that pointer (*ranks) to get one of the array elements as an lvalue.

Just don't ask me what an lvalue is. I know it when I see it. :)

Tested on gcc.

cxw
  • 16,685
  • 2
  • 45
  • 81
  • If I add a statement 'int x = 5' and 'ranks = &x', can't we say that 'ranks' refer to object? – Jin Aug 17 '16 at 17:06
  • @Jin If `ranks` is `int ranks[10]`, `ranks=&x` won't compile. It would compile for `int *ranks;`. This is one of the situations in which arrays and pointers are not perfectly interchangeable. – cxw Aug 17 '16 at 17:08
  • @Jin: you can't assign to `ranks`; array expressions cannot be the target of an assignment operator. – John Bode Aug 17 '16 at 17:08