This section introduces operators that are unusual in the sense that we have no everyday analogs to them. Nevertheless, most are very useful, frequently used in programs, and worth taking the time to understand. The last two operators covered here, sizeof
and the comma operator, are less common and less useful, but we cover them briefly for completeness.
There are two auto increment operators, x++ and ++x, and two auto decrement operators, x-- and --x. In all four versions, x must be a variable. (That requirement is an oversimplification: it can be an l-value, but requiring a variable is sufficient for now). When the operators precede (i.e., come before) the variable, the operations are called pre-increment and pre-decrement; when the operators succeed (i.e., come after) the variable, the operations are called post-increment and post-decrement. In the pre- and post-operations, the value stored in x is either incremented (++) or decremented (--) by 1. We only see the difference between the pre- and post-operations when the program embeds them in a larger expression where the evaluation order is significant.
When we embed the increment and decrement operations in larger expressions, thinking about "using the value" can help us understand their behavior. The increment and decrement operators accomplish two distinct sub-operations. Like all operators, they calculate an expression value, but they also change the value stored in a variable. The key to understanding their behavior is the relative order in which they "use" or access the value stored in the variable and when they change it.
Operator | Meaning | Result | Description |
---|---|---|---|
a = x++; | a = x; x = x + 1; |
a == 10 x == 11 |
Store 10 (use x) in a, then increment x to 11 |
a = ++x; | x = x + 1; a = x; |
a == 11 x == 11 |
Increment x to 11, then store 11 (use x) in a |
a = x--; | a = x; x = x - 1; |
a == 10 x == 9 |
Store 10 (use x) in a, then decrement x to 9 |
a = --x; | x = x - 1; a = x; |
a == 9 x == 9 |
Decrement x to 9, then store 9 (use x) to a |
Operation with assignment is a shorthand notation, most often used with the arithmetic operators, but we may also use it with the relational and binary bitwise operators. The left-hand operand must always be a variable, but the right-hand operand can be an arbitrarily complex expression.
|
int dollars = pennies / 100; pennies %= 100; int quarters = pennies / 25; pennies %= 25; int dimes = pennies / 10; pennies %= 10; int nickels = pennies / 5; pennies %= 5; |
(a) | (b) |
x 🙂= expression
is a shortcut for x = x 🙂 expression
.
The conditional operator is the only tertiary operator (i.e., an operator that takes three operands) in C++ (or in Java) and consists of two symbols, ?
and :
, that separate the three operands:
The conditional operator is a convenient and compact way of performing a simple conditional calculation. Assuming that x and y are appropriately defined and initialized integer variables, the following code fragments produce the same results:
int min = (x < y) ? x : y; |
int min; if (x < y) min = x; else min = z; |
(a) | (b) |
sizeof
is an "unusual" operator in at least two ways. First, we tend to think of operators as consisting of non-alphabetic symbols like +
or *
, whereas sizeof
is a word (well, two words joined together). Second, sizeof
is unique because the compiler evaluates it rather than the program when it executes. The compiler replaces the sizeof
expression with a constant value rather than generating executable code. So, sizeof
produces the size as the number of bytes of memory needed to store some data. The data can be (a) a data type name, (b) a specific variable, or (c) a constant. For example:
We rarely need the sizeof
operator in practice, but we occasionally use it to write platform-independent code when the code itself depends on the data size. For example, recall that the size of an int
can vary between 2, 4, or 8 bytes from one computer to another. The following example uses the sizeof
operator to determine the size of (i.e., how many bytes are in) an integer. Then, it uses that size to convert a number to binary and display the result.
The comma operator is used even less often than is the sizeof
operator; nevertheless, it's important to know about it - as much to avoid misusing it as to use it correctly. The comma operator allows chaining two or more expressions together: E1, E2, E3, ..., En. The comma operator evaluates the expressions left to right, discards the values of the first En-1 expressions, and the overall value of the joined expressions is the value of the last expression or En. It might seem pointless to evaluate an expression only to discard its value, but in addition to creating a value, expressions can also have useful side effects.
In this context, a side effect is a secondary change to a program (e.g., changing the value stored in a variable) beyond returning a value. It's much easier to understand side effects and the comma operator with a set of examples. First, recall that the assignment operator returns a value, which forms the basis of our examples.
y = 5; | x = y = 5; | z = (x = 5, y = 2); |
(a) | (b) | (c) |
y = 5
produces the value 5 (i.e., the statement cout << y = 5 << endl;
prints "5" to the console). The example ignores the assignment side effect of storing 5 in y.y = 5
first. This sub-expression has the useful side effect of storing 5 in y. However, the assignment operator forms an expression, producing the value 5. So, the second expression, x = y = 5
, then stores the value 5, returned by the first sub-expression, into variable x.x = 5
, stores 5 in x and returns 5; the second sub-expression, y = 2
, stores 2 in y and returns 2. The comma operator evaluates x = 5, y = 2
, discarding the value of the first sub-expression. So, the overall value of the top-level expression is 2 (the value of the last sub-expression), which the assignment operator saves in the variable z.The comma operator is most often used in for-loops (Chapter 3). Underscoring this conclusion is the observation that for-loops are the only place Java allows the comma operator. The comma operator allows programmers to form a compound expression that evaluates two or more sub-expressions where the syntax only allows a single expression: