An expression is anything that evaluates to a value: a literal like 42, a variable name, a function call, or some combination of these joined by operators.
int x = 10;
int y = 5;
int sum = x + y; // expression: x + y → 15
bool ok = (sum > 10); // expression: sum > 10 → trueThis chapter covers the operators you will use day-to-day, and the rule that decides what happens when several of them appear in the same expression.
| Operator | Meaning | Example | Result |
|---|---|---|---|
+ |
addition | 5 + 3 |
8 |
- |
subtraction | 5 - 3 |
2 |
* |
multiplication | 5 * 3 |
15 |
/ |
division | 10 / 3 |
3 (with int) or 3.333… (with double) |
% |
remainder (modulo) | 10 % 3 |
1 |
Integer division truncates. This is the single most common arithmetic surprise:
int a = 10 / 3; // 3, fractional part discarded
double b = 10 / 3; // 3.0, not 3.333 — divided as int first, then converted
double c = 10.0 / 3; // 3.333…, at least one operand is doubleIf you want a decimal result, at least one operand must be a double or float.
% (modulo) only works on integer types. 10 % 3 is 1; 10.0 % 3 is a compile error.
int total = 0;
total = total + 5; // long form
total += 5; // same thing, shorterThe compound forms +=, -=, *=, /=, %= all work the same way: read the current value, apply the operation, write back.
++ and -- increment or decrement by one:
int i = 0;
++i; // i is now 1, preferred form
i++; // also works, prefer ++i when used on its ownFor built-in types ++i and i++ behave identically when used as a standalone statement. They differ when used inside a larger expression (++i returns the new value, i++ returns the old one), but using ++ inside an expression you also assign from is a quick way to confuse yourself. Don't.
Comparison operators produce a bool:
| Operator | Meaning |
|---|---|
== |
equal |
!= |
not equal |
< |
less than |
> |
greater than |
<= |
less than or equal |
>= |
greater than or equal |
bool adult = (age >= 18);The most common bug here: writing = (assignment) when you mean == (comparison).
if (x = 5) { ... } // assigns 5 to x, then tests if 5 is true, always runs
if (x == 5) { ... } // tests whether x equals 5Modern compilers warn about this if you enable warnings. Turn them on.
Used to combine boolean expressions:
| Operator | Meaning |
|---|---|
&& |
AND: true only if both sides are true |
|| |
OR: true if either side is true |
! |
NOT: flips true and false |
if (temperature > 80 && pressure < 5) {
// both conditions must hold
}
if (!ready) {
// 'ready' is false
}&& and || are short-circuiting: they evaluate the right-hand side only if needed. This is useful — and occasionally essential:
if (count != 0 && total / count > threshold) {
// safe: total / count runs only when count is not zero
}If count is zero, the right side never runs, so the division is skipped. Swap the two conditions and the program divides by zero.
A compact if/else that produces a value:
int max = (a > b) ? a : b;Reads as: "if a > b, the value is a; otherwise it is b." Convenient for short choices. For anything more complex, use a real if/else statement; readability beats brevity.
When several operators appear in the same expression, precedence decides which binds tighter.
int x = 2 + 3 * 4; // 14, not 20, * binds tighter than +The full precedence table is long. You do not need to memorise it. You need to remember two rules and you will not get in trouble:
*,/,%bind tighter than+and-(standard maths).- When in doubt, use parentheses. They cost nothing and make intent explicit.
Operators of equal precedence evaluate left to right, which can catch you out:
int result = totalSeconds / 60 * 60;You might read that as "divide by 60, then multiply by 60 — back where you started." It is not: the / runs first, and integer division discards the remainder. With totalSeconds = 125, 125 / 60 is 2, and 2 * 60 is 120 — not 125. Now a different trap, where the grouping is unclear:
double rate = a + b / c + d;Did you mean (a + b) / (c + d) or a + (b/c) + d? They give different answers. Write the parentheses you mean.
If you combine values of different types, C++ converts them following well-defined rules. Two cases worth knowing:
int i = 5;
double d = 2.0;
double result = i + d; // i is promoted to double; result is 7.0That is the safe direction: int to double loses nothing.
double pi = 3.14;
int n = pi; // truncates to 3, fractional part lostGoing the other direction (double to int) silently loses information. Brace initialisation refuses it; ordinary assignment does not. If you want to truncate, make it explicit with a cast:
int n = static_cast<int>(pi);static_cast is the polite way to ask for a conversion the compiler would otherwise warn about. It also flags to a reader that the truncation is intentional.
Avoid the C-style cast. You will also see the older form,
(int)pi. Preferstatic_cast: a C-style cast silently performs whatever conversion is needed — including unsafe ones that a named cast would reject — and a bare(int)is nearly impossible to search your code for.static_cast<int>(pi)states exactly what you mean and lets the compiler keep you honest.
- Arithmetic on integers truncates; mix in a
doubleto get decimal results. ==compares,=assigns. They are not the same.&&and||short-circuit, which is useful for guarding against null/invalid values.- Precedence exists, but parentheses are free. Use them.
- Conversions from larger to smaller types lose data silently; make them explicit with
static_cast, not the old C-style(int)x.
Floating-point arithmetic has surprises of its own: 0.1 + 0.2 does not exactly equal 0.3, and comparing floats with == is almost never what you want. See the Floating-Point Pitfalls reference for the full list of gotchas.