Section 5.4. Assignment Operators


5.4. Assignment Operators

The left-hand operand of an assignment operator must be a nonconst lvalue. Each of these assignments is illegal:

      int i, j, ival;      const int ci = i;  // ok: initialization not assignment      1024 = ival;       // error: literals are rvalues      i + j = ival;      // error: arithmetic expressions are rvalues      ci = ival;         // error: can't write to ci 

Array names are nonmodifiable lvalues: An array cannot be the target of an assignment. Both the subscript and dereference operators return lvalues. The result of dereference or subscript, when applied to a nonconst array, can be the left-hand operand of an assignment:

      int ia[10];      ia[0] = 0;    // ok: subscript is an lvalue      *ia = 0;      // ok: dereference also is an lvalue 

The result of an assignment is the left-hand operand; the type of the result is the type of the left-hand operand.

The value assigned to the left-hand operand ordinarily is the value that is in the right-hand operand. However, assignments where the types of the left and right operands differ may require conversions that might change the value being assigned. In such cases, the value stored in the left-hand operand might differ from the value of the right-hand operand:

      ival = 0;        // result: type int value 0      ival = 3.14159;  // result: type int value 3 

Both these assignments yield values of type int. In the first case the value stored in ival is the same value as in its right-hand operand. In the second case the value stored in ival is different from the right-hand operand.

5.4.1. Assignment Is Right Associative

Like the subscript and dereference operators, assignment returns an lvalue. As such, we can perform multiple assignments in a single expression, provided that each of the operands being assigned is of the same general type:

      int ival, jval;      ival = jval = 0; // ok: each assigned 0 

Unlike the other binary operators, the assignment operators are right associative. We group an expression with multiple assignment operators from right to left. In this expression, the result of the rightmost assignment (i.e., jval) is assigned to ival. The types of the objects in a multiple assignment either must be the same type or of types that can be converted (Section 5.12, p. 178) to one another:

      int ival; int *pval;      ival = pval = 0; // error: cannot assign the value of a pointer to an int      string s1, s2;      s1 = s2 = "OK";  // ok: "OK" converted to string 

The first assignment is illegal because ival and pval are objects of different types. It is illegal even though zero happens to be a value that could be assigned to either object. The problem is that the result of the assignment to pval is a value of type int*, which cannot be assigned to an object of type int. On the other hand, the second assignment is fine. The string literal is converted to string, and that string is assigned to s2. The result of that assignment is s2, which is then assigned to s1.

5.4.2. Assignment Has Low Precedence

Inside a condition is another common place where assignment is used as a part of a larger expression. Writing an assignment in a condition can shorten programs and clarify the programmer's intent. For example, the following loop uses a function named get_value, which we assume returns int values. We can test those values until we obtain some desired valuesay, 42:

      int i = get_value();  // get_value returns an int      while (i != 42) {          // do something ...          i = get_value(); } 

The program begins by getting the first value and storing it in i. Then it establishes the loop, which tests whether i is 42, and if not, does some processing. The last statement in the loop gets a value from get_value(), and the loop repeats. We can write this loop more succinctly as

      int i;      while ((i = get_value()) != 42) {          // do something ...      } 

The condition now more clearly expresses our intent: We want to continue until get_value returns 42. The condition executes by assigning the result returned by get_value to i and then comparing the result of that assignment with 42.

The additional parentheses around the assignment are necessary because assignment has lower precedence than inequality.



Without the parentheses, the operands to != would be the value returned from calling get_value and 42. The true or false result of that test would be assigned to iclearly not what we intended!

Beware of Confusing Equality and Assignment Operators

The fact that we can use assignment in a condition can have surprising effects:

      if (i = 42) 

This code is legal: What happens is that 42 is assigned to i and then the result of the assignment is tested. In this case, 42 is nonzero, which is interpreted as a true value. The author of this code almost surely intended to test whether i was 42:

      if (i == 42) 

Bugs of this sort are notoriously difficult to find. Some, but not all, compilers are kind enough to warn about code such as this example.

Exercises Section 5.4.2

Exercise 5.11:

What are the values of i and d after the each assignment:

      int i;   double d;      d = i = 3.5;      i = d = 3.5; 

Exercise 5.12:

Explain what happens in each of the if tests:

      if (42 = i)   // . . .      if (i = 42)   // . . . 


5.4.3. Compound Assignment Operators

We often apply an operator to an object and then reassign the result to that same object. As an example, consider the sum program from page 14:

      int sum = 0;      // sum values from 1 up to 10 inclusive      for (int val = 1; val <= 10; ++val)          sum += val; // equivalent to sum = sum + val 

This kind of operation is common not just for addition but for the other arithmetic operators and the bitwise operators. There are compound assignments for each of these operators. The general syntactic form of a compound assignment operator is

      a op= b; 

where op= may be one of the following ten operators:

      +=   -=   *=   /=   %=   // arithmetic operators      <<= >>=   &=   ^=   |=   // bitwise operators 

Each compound operator is essentially equivalent to

      a = a op b; 

There is one important difference: When we use the compound assignment, the left-hand operand is evaluated only once. If we write the similar longer version, that operand is evaluated twice: once as the right-hand operand and again as the left. In many, perhaps most, contexts this difference is immaterial aside from possible performance consequences.

Exercises Section 5.4.3

Exercise 5.13:

The following assignment is illegal. Why? How would you correct it?

      double dval; int ival; int *pi;      dval = ival = pi = 0; 

Exercise 5.14:

Although the following are legal, they probably do not behave as the programmer expects. Why? Rewrite the expressions as you think they should be.

      (a) if (ptr = retrieve_pointer() != 0)      (b) if (ival = 1024)      (c) ival += ival + 1; 




C++ Primer
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2006
Pages: 223
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net