Answer: We already know that lvalue refers to some location or storage used by some data object, for example: variables, arrays, structures, pointers etc. Further, ‘l’ in lvalue stands for left side of assignment “=” operator meaning that left side of assignment must be an expression which results in some location in memory. Let’s take a few examples:
int index = 0; /* index, an integer, is initialized with 0 */ char address[100]; /* address, an array of 100 characters * float avg_rain; /* avg_rain has some garbage */ float temperature; float *fp = &avg_rain; /* * *fp, a pointer-to-float, is initialized with address of float * 'avg_rain' */
All the above data objects are stored in memory at specified locations. Their addresses can be obtained by using unary operator called addressof operator ‘&’. Addressof operator returns address of first byte of storage allocated to the data object.
Now, see, if constants are allocated to specified locations, can we determine their addresses using addressof operator? We take some examples:
500; 45.0; /* all these are constants * 'A';
All the above constants are stored in memory but where? We can’t know this? Actually, constants don’t have lvalues. And that’s why we can’t assign them values! Let’s try to find their addresses:
/* * determine_add_const.c -- Program shows if we can determine address of * constants */ #include <stdio.h> int main(void) { 500; /* integer constant */ 45.06; /* float constant */ 'A'; /* character constant */ printf("Address of integer '500' is %p\n", &(500)); printf("Address of float '45.06' is %p\n", &(45.06)); printf("Address of character \'A\' is %p\n", &('A')); return 0; }
Output as below:
[root@localhost ch06_Pointers]# gcc determine_add_const.c determine_add_const.c: In function ‘main’: determine_add_const.c:9:43: error: lvalue required as unary ‘&’ operand determine_add_const.c:10:43: error: lvalue required as unary ‘&’ operand determine_add_const.c:11:45: error: lvalue required as unary ‘&’ operand
Note that addressof operator operates on operands having lvalues. Constants don’t have!
O key! Now, we try to modify the above mentioned data objects, below:
int index = 100; /* now index is assigned 100 */ char address[100]; /* address is an array of 100 characters */ float avg_rain = 3.203; /* avg_rain is assigned 3.203 */ *fp = &temperature; /* *fp is assigned address of float temperature */
Because the left side of the assignment can be modified, lvalue is properly referred to as modifiable lvalue.
Until now, we are cleared with what an lvalue is! Let’s further talk about it with reference to pointer expressions. Addressof operator ‘&’ and indirection / dereferencing operator ‘*’ are frequently used with pointers. Let’s unravel some pointer expressions to understand how these two operators work, for example:
int men = 100, women = 150; int *ip = &men; /* *ip = &men, assigns 'ip' address of location where men is stored */
In exp. “*ip = &men”, pointer to integer ‘ip’ points to location of men in the memory. To access the value of men using ‘ip’, we need to perform indirection on ‘ip’. Let’s see how,
printf("There are %d men working in a factory.\n", *ip);
Let’s interpret a simple exp. *ip. ‘ip’ holds the address of location of men. When we performed indirection on ‘ip’, it caused to go to location pointed to by ‘ip’, that is location of men, and access the value there, whether to read value from or to write value there. That’s why ‘*ip’ represents both as value and location and hence is an lvalue.
Take some little bit complex pointer exp., for example:
int NH_India = 228; int *ip = &NH_India; int new; new = ++*ip;
In the exp. “new = ++*ip”, ++ and * are unary operators have associativity from right to left. So indirection is applied first and value at the location pointed to by ‘ip’ is taken, which is here 228. Then pre-increment operator to operate. But pre-increment operator increments its operand by 1, then makes a copy of incremented value and use that copy in the surrounding expression. See program below:
/* ptrexp_as_lvalue1.c -- program shows pointer expressions */ #include <stdio.h> int main(void) { int NH_India = 228; int *ip = &NH_India; int new; printf("When \"new\" not initialized it is %d and NH_India is %d\n", new, NH_India); new = ++*ip; printf("After \"new = ++*ip\", new is %d and NH_India is %d\n", new, NH_India); return 0; }
Output of the above program:
[root@localhost ch06_Pointers]# gcc ptrexp_as_lvalue1.c [root@localhost ch06_Pointers]# ./a.out When "new" not initialized it is 32767 and NH_India is 228 After "new = ++*ip", new is 229 and NH_India is 229
Notice, integer ‘NH_India’ is incremented by 1. But if exp. ++*ip represents an lvalue? Can we write
new = ++*ip; as ++*ip = new; /* if allowed? */
Of course, not! Why? Because, we have already seen above that ‘++*ip’ gives an integer value and not a location.
/* ptrexp_as_lvalue2.c -- program shows pointer expressions as lvalues */ #include <stdio.h> int main(void) { int NH_India = 228; int *ip = &NH_India; int new = 100; printf("When \"new\" initialized it is %d and NH_India is %d\n", new, NH_India); ++*ip = new; /* if allowed? */ printf("After \"++*ip = new\", ++*ip is %d and NH_India is %d\n", new, NH_India); return 0; }
Output is below:
[root@localhost ch06_Pointers]# gcc ptrexp_as_lvalue2.c ptrexp_as_lvalue2.c: In function ‘main’: ptrexp_as_lvalue2.c:11:15: error: lvalue required as left operand of assignment
Note the error: lvalue required as left operand of assignment. What if we write the expression as:
++*ip; as *ip++;
Again, there are two operators * and ++. But this time ++ is used as post increment operator and post increment operator has higher precedence than ‘*’ operator. Let’s continue to emphasize on their working. Remember that pre and post increment operators create copies of values of their operands and that copy is used in the surrounding exp.. Also remember that in case of pre-increment, copy is created after operand is modified while in post-increment copy is created before operand is incremented.
So, in exp. “*ip++”, ‘++’ operates first, copy of value of ‘ip’, which is address of integer NH_India, is created, then pointer ‘ip’ is incremented to point to next integer and then indirection is performed on copy and value at the location pointer ‘ip’ was pointing to before increment is assigned to new.
new = *ip++;
/* * ptrexp_as_lvalue3.c -- program shows where pointer points to when * incremented */ #include <stdio.h> int main(void) { int NH_India = 228; int *ip = &NH_India; int new = 100; printf("When \"new\" initialized it is %d and value of *ip is %p\n", new, ip); new = *ip++; printf("After \"new = *ip++\", new is %d and \"new value\" of *ip is " ."%p\n", new, ip); .return 0; }
Look closely at the output below:
[root@localhost ch06_Pointers]# gcc ptrexp_as_lvalue3.c [root@localhost ch06_Pointers]# ./a.out When "new" initialized it is 100 and value of *ip is 0x7fffe9828340 After "new = *ip++", new is 228 and "new value" of *ip is 0x7fffe9828344
Notice pointer *ip’s earlier and current values. Although, *ip is incremented by 1 it’s value changed from 0x7fffe9828340 to 0x7fffe9828344. Actually, when we say, a pointer is incremented by 1, we mean it’s moved forward by one storage unit of the type it’s pointing to.
Now, we see what happens when we set the exp. “*ip++” on the left side of assignment.
*ip++ = new;
Again, ‘*ip++’ doesn’t represent a location but a value. And a value can’t be assigned any other value. Therefore, this statement results in lvalue error.
There are numerous pointer expressions which are lvalues and used frequently in programs. However, on the other side, not all pointer expressions are lvalues.
Examples of pointer expressions having lvalues:
*ip; *++ip; *ip++;
Examples of pointer expressions with no valid lvalues:
++*++ip; ip++; and ip++; (*ip)++; ++*ip++;
Note, you can apply above given reasoning to understand pointer expressions, in examples above, which are lvalues and which aren’t.
Sanfoundry Global Education & Learning Series – 1000 C Tutorials.
- Practice Computer Science MCQs
- Apply for C Internship
- Watch Advanced C Programming Videos
- Check C Books
- Apply for Computer Science Internship