
Expressions and Operators
The operations of C++ are divided into the arithmetic, relational, logical, and bitwise operators as well as simple and compound assignment. Moreover, there is the conditional operator.
In the figure below, + is an operator, a and b are operands, and the whole term is an expression.

Arithmetic Operators
The arithmetic operators are addition (+), subtraction (-), multiplication (*), division (/), and modulo (%). The first four operators are equivalent to the four fundamental rules of arithmetic. The operators can take operands of integral and floating types. The last operator—modulo—gives the remainder of integer division. If we mix integral and floating types in the expression, the result will have floating type. The modulo operator, however, can only have integral operands. The last assignment in the following code may give rise to a compiler warning as the result of the division is a double and is converted into an int.
int a = 10, b = 3, c; c = a + b; // 13 c = a - b; // 7 c = a * b; // 30 c = a / b; // 3, integer division c = a % 3; // 1, remainder double d = 3.0; c = a / d; // 3.333, floating type
Pointer Arithmetic
The addition and subtraction operators are also applicable to pointers. It is called pointer arithmetic. An integral value can be added to or subtracted from a pointer. The value of the pointer is then changed by the integral value times the size of the type the pointer points at. As the void type is not really a type, but rather the absence of a type, it has no size. Therefore, we cannot perform pointer arithmetic on pointers to void.
In the code below, let us assume that iNumber
is stored at memory location 10,000 and that the integer type has the size of four bytes. Then the pointer pNumber
will assume the values 10,000, 10,004, 10,008, and 10,012, not the values 10,000, 10,002, 10,003, and 10,013, as pointer arithmetic always take the size of the type into consideration.

int iNumber = 100; int* pNumber = &iNumber; pNumber = pNumber + 1; *pNumber = iNumber + 1; pNumber = pNumber + 1; *pNumber = iNumber + 2; pNumber = pNumber + 1; *pNumber = iNumber + 3;
It is also possible to subtract two pointers pointing at the same type. The result will be the difference in bytes between their two memory locations divided by the size of the type.
int array[] = {1, 2, 3}; int* p1 = &array[0]; int* p2 = &array[2]; int iDiff = p2 - p1; // 2
The index notation for arrays is equivalent to the dereferring of pointers together with pointer arithmetic. The second and third lines of the following code are by definition interchangeable.
int array[] = {1, 2, 3}; array[1] = array[2] + 1; *(array + 1) = *(array + 2) + 1;
Increment and Decrement
T here are two special operators: increment (++) and decrement (--). They add one to or subtract one from its operand. The operator can be placed before (prefix) or after (postfix) its operand.
int a = 1, b = 1; ++a; // 2, prefix increment b++; // 2, postfix increment
However, there is a difference between prefix and postfix increment/decrement. In the prefix case, the subtraction occurs first and the new value is returned; in the postfix case, the original value is returned after the subtraction.
int a = 1, b = 1, c, d; c = --a; // c = 0, prefix decrement d = b--; // d = 1, postfix decrement
Relational Operators
There are six relational operators: equal to (==), not equal to (!=), less than (<), less than or equal to (<=), greater than (>), and greater than or equal to (>=). Note that the equal to operator is constituted by two equals signs rather than one (one equals sign represents the assignment operator). The operators give a logical value, true or false. The operands shall be of integral or floating type.
int i = 3; double x = 1.2; bool b = i > 0; // true bool c = x == 2; // false
Logical Operators
There are three logical operators: not (!), or (||), and and (&&). They take and return logical values of the boolean type.
int i = 3; bool b, c, d, e; b = (i == 3); // true c = !b; // false d = b || c; // true e = b && c; // false
C++ applies lazy (also called short-circuit) evaluation, which means that it will not evaluate more parts of the expression than is necessary to evaluate its value. In the following example, the evaluation of the expression is completed when the left expression (i != 0) is evaluated to false. If the left expression is false, the whole expression must also be false because it needs both the left and right expressions to be true for the whole expression to be true. This shows that the right expression (1 / i == 1) will never be evaluated and the division with zero will never occur.
int i = 0; bool b = (i != 0) && (1 / i == 1); // false;
Bitwise Operators
An integer value can be viewed as a bit pattern. Our familiar decimal system has the base ten; it can be marked with an index 10.
23410=>2.100+3.10+4.1=2.102+3.101+4.100
An integer value can also be viewed with the binary system, it has the base two. A single digit viewed with the base two is called a bit, and the integer value is called a bit pattern. A bit may only take the values one and zero.
10102=>1.23+0.22+1.21+0.20=1.8+0.4+1.2+0.1=8+2=0
There are four bitwise operations in C++: inverse (~), and (&), or (|), and exclusive or (^). Exclusive or means that the result is one if one of its operand bits (but not both) is one. They all operate on integral values on bit level; that is, they examine each individual bit of an integer value.
101010102 101010102 101010102 & 100101102 | 100101102 ^ 100101102 ~ 100101102 ----------- ------------ ------------ ------------ = 100000102 = 101111102 = 001111002 = 011010012 int a = 170; // 101010102 int b = 150; // 100101102 int c = a & b; // 100000102 = 13010 int d = a | b; // 101111102 = 19010 int e = a ^ b; // 001111002 = 6010 int f = ~b; // 011010012 = 10510
An integer value can also be shifted to the left (<<) or to the right (>>). Do not confuse these operators with the stream operators; they are different operators that happen to be represented by the same symbols. Each left shift is equivalent to doubling the value, and each right shift is equivalent to (integer) dividing the value by two. Overflowing bits are dropped for unsigned values; the behavior of signed values is implementation-dependent.
unsigned char a = 172; // 10101100, base 2 unsigned char b = a << 2; // 10110000, base 2 = 160, base 10 unsigned char c = 166; // 10100110, base 2 unsigned char d = c >> 2; // 00101001, base 2 = 41, base 10 cout << (int) a << " " << (int) b << " " << (int) c << " " << (int) d << endl;
Assignment
There are two kinds of assignment operators: simple and compound. The simple variant is quite trivial, one or more variables are assigned the value of an expression. In the example below, a, b, and c are all assigned the value 123.
int a, b, c, d = 123; a = d; b = c = d;
The compound variant is more complicated. Let us start with the additional assignment operator. In the example below, a
's value is increased by the value of b
; that is, a is given the value 4
.
int a = 2, b = 4, c = 2; a += c; // 4, equivalent to a = a + c. b -= c; // 2, equivalent to a = a - c.
In a similar manner, there are operations -=, *=, /=, %=, |=, &=, and ^= as well as |=, &=, ^=, <<=, and >>=.
The Condition Operator
The condition operator resembles the if-else
statement of the next section. It is the only C++ operator that takes three operands. The first expression is evaluated. If it is true, the second expression is evaluated and its value is returned. If the first expression instead is false, the third expression is evaluated and its value is returned.
int a = 1, b = 2, max; max = (a > b) ? a : b; // The maximal value of a and b.
Too frequent use of this operator tends to make the code compact and hard to read. A piece of advice is that to restrict your use of the operator to the trivial cases.
Precedence and Associativity
Given the expression 1 + 2 * 5, what is its value? It is 11 because we first multiply two with five and then add one. We say that multiplication has a higher precedence than addition.
What if we limit ourselves to one operator, let us pick subtraction. What is the value of the expression 8 – 4 – 2? As we first subtract four from eight and then subtract two, the result is two. As we evaluate the value from left to right, we say that subtraction is left associative.
Below follows a table showing the priorities and associativities of the operator of C++. The first operator in the table has the highest priority.

Note that unary +, -, and * have higher priority than their binary forms. Also note that we can always change the evaluation order of an expression by inserting brackets at appropriate positition. The expression (1 + 2) * 5 has the value 15.