C++ Notes
() first, then multiplication *, division /, and modulus %, then addition + and subtraction -.Prefix is preferred in most cases. Postfix is only worth reaching for when you specifically need the old value before the increment happens.
| Form | Behavior |
|---|---|
++value (prefix) | Increments first, then the new value is used in the same expression. |
--value (prefix) | Decrements first, then the new value is used. |
value++ (postfix) | The current value is used first, and it increments only for the next use. |
value-- (postfix) | The current value is used first, and it decrements only for the next use. |
Shorthand for performing an operation and assigning the result back to the same variable.
| Longhand | Shorthand |
|---|---|
value = value + 1; | value += 1; |
value = value / 2; | value /= 2; |
value = value * 10; | value *= 10; |
The same pattern applies for -=, %=, and every other arithmetic operator.
Used to compare values. The result is always true or false, which prints as 1 or 0.
| Operator | Meaning |
|---|---|
> | greater than |
< | less than |
>= | greater than or equal to |
<= | less than or equal to |
== | equality check |
!= | inequality check |
Wrap a comparison in brackets when using it inside cout: std::cout << (num1 > num2) << '\n'; prints 1 or 0. Without the brackets, << can get parsed before the comparison and give you a result you didn't expect.
| Operator | Behavior |
|---|---|
&& (AND) | Combines two or more conditions. Returns true only if every condition is true. |
|| (OR) | Combines two or more conditions. Returns false only if every condition is false. |
! (NOT) | Negates a condition. !true becomes false, !false becomes true. |
#include <iomanip> provides setw(), setprecision(), and setfill().#include <ios> provides alignment, base, notation, and other stream state manipulators. It's usually pulled in automatically through <iostream>, but including it explicitly is cleaner.| Manipulator | What It Does | Example |
|---|---|---|
'\n' | Adds a newline character. Does not flush the buffer. | — |
std::flush | Flushes the buffer without adding a newline. | — |
std::endl | Adds a newline and flushes the buffer. Slower than '\n' for that reason. | — |
std::setw(n) | Sets the minimum field width for the next output only. If the text is shorter, a fill character is added. If longer, nothing gets cut. | "Hassan" with setw(10) → " Hassan" |
std::left | Aligns text to the left, padding on the right. | "Left |" |
std::right | Aligns text to the right, padding on the left. This is the default. | " Right|" |
std::internal | Places padding between the sign and the number. Only affects signed numbers and base prefixes, does nothing for plain strings. | -42 with width 6 → "- 42" |
std::setfill(c) | Sets the fill character instead of the default space. | setfill('-') + setw(10) + "Ali" → "-------Ali" |
std::boolalpha | Prints bool as true/false instead of 1/0. Disable with std::noboolalpha. | true → "true" |
std::showpos | Adds a + sign to positive numbers. Negative numbers already show their sign regardless. Disable with std::noshowpos. | 25 → "+25" |
std::dec | Prints integers in decimal. Also used to reset back from hex or octal. | 717171 → "717171" |
std::hex | Prints integers in hexadecimal. Has no effect on floating point values. | 717171 → "af173" |
std::oct | Prints integers in octal. Has no effect on floating point values. | 717171 → "2570573" |
std::showbase | Adds the base prefix to output. Disable with std::noshowbase. | hex → "0xaf173", oct → "02570573" |
std::uppercase | Uppercases hex digits and scientific notation. Does not affect strings, boolalpha, or chars. Disable with std::nouppercase. | "af173" → "AF173" |
std::fixed | Forces fixed-point notation. Once set, setprecision means digits after the decimal point. Very small numbers may show as 0. | setprecision(3): 12.3 → "12.300" |
std::scientific | Forces scientific notation. setprecision means digits after the decimal point of the exponent form. | setprecision(4): 0.00123456 → "1.2346e-03" |
std::setprecision(n) | Controls how many digits get printed. Default is 6 significant digits. Does not affect the stored value. | setprecision(3): 123.456789 → "123" |
std::showpoint | Shows trailing zeros up to the set precision for floating point. Has no effect on int. Disable with std::noshowpoint. | setprecision(5): 34.1 → "34.100" |
To reset fixed or scientific back to the default auto notation: std::cout.unsetf(std::ios::scientific | std::ios::fixed);
| Category | Meaning | Which Manipulators |
|---|---|---|
| Temporary 1-shot | Affects the very next output only, then resets automatically. | std::setw(n) |
| Permanent sticky | Changes the stream's state and stays active for all future output until you explicitly change it back. | Every other manipulator above: setfill, setprecision, left, right, hex, fixed, and so on. |
| No state action | A one-time action with no persistence at all, there's no "state" to reset. | '\n', std::endl, std::flush |
This is the one thing about output formatting that trips people up the most: setw(10) quietly stops applying after a single use, while std::hex keeps every number in hex until you explicitly switch back with std::dec. Knowing which bucket a manipulator falls into saves you from chasing formatting bugs that are actually just leftover state from three lines earlier.
#include <iostream> #include <iomanip> #include <ios> int main() { std::cout << "01) '\\n'\n"; std::cout << "Line 1\n"; std::cout << "Line 2\n\n"; std::cout << "02) std::flush;\n"; std::cout << "Flushing buffer..." << std::flush << "\n\n"; // flushes but no newline added by flush std::cout << "03) std::endl;\n"; std::cout << "Using endl" << std::endl; // newline + flush std::cout << "\n16) std::setprecision(3);\n"; double sep = 123.456789; std::cout << std::setprecision(3) << sep << "\n\n"; // prints: 123 std::cout << "04) std::setw(10);\n"; std::cout << std::setw(10) << "Hassan" << "\n\n"; // prints: " Hassan" std::cout << "05) std::left / std::right / std::internal;\n"; std::cout << std::left << std::setw(10) << "Left" << "|\n"; // prints: "Left |" std::cout << std::right << std::setw(10) << "Right" << "|\n"; // prints: " Right|" std::cout << std::internal << std::setw(6) << -42 << "\n\n"; // prints: "- 42" std::cout << "06) std::setfill();\n"; std::cout << std::setfill('-') << std::setw(10) << "Ali" << "\n"; // prints: "-------Ali" std::cout << std::setfill(' ') << "\n"; // reset fill back to space std::cout << "07) std::boolalpha;\n"; std::cout << std::boolalpha << true << " " << false << "\n"; // prints: "true false" std::cout << std::noboolalpha << true << " " << false << "\n\n"; // prints: "1 0" std::cout << "08) std::showpos;\n"; std::cout << std::showpos << 25 << " " << -25 << "\n"; // prints: "+25 -25" std::cout << std::noshowpos << 25 << " " << -25 << "\n\n"; // prints: "25 -25" std::cout << "09) std::dec;\n"; std::cout << std::dec << 717171 << "\n\n"; // prints: 717171 std::cout << "10) std::hex;\n"; std::cout << std::hex << 717171 << "\n\n"; // prints: af173 std::cout << "11) std::oct;\n"; std::cout << std::oct << 717171 << "\n\n"; // prints: 2570573 std::cout << "12) std::showbase;\n"; std::cout << std::showbase << std::hex << 717171 << "\n"; // prints: 0xaf173 std::cout << std::oct << 717171 << "\n"; // prints: 02570573 std::cout << std::noshowbase << std::dec << 717171 << "\n\n"; // prints: 717171 std::cout << "13) std::uppercase;\n"; std::cout << std::uppercase << std::hex << 717171 << "\n"; // prints: AF173 std::cout << std::nouppercase << std::hex << 717171 << "\n"; // prints: af173 std::cout << std::dec << "\n"; // reset back to decimal std::cout << "14) std::fixed;\n"; double value = 12.345678; std::cout << std::fixed << std::setprecision(3) << value << "\n\n"; // prints: 12.346 std::cout << "15) std::scientific;\n"; std::cout << std::scientific << std::setprecision(4) << value << "\n\n"; // prints: 1.2346e+01 std::cout.unsetf(std::ios::scientific | std::ios::fixed); // reset to default auto notation std::cout << "17) std::showpoint;\n"; std::cout << std::setprecision(5); std::cout << std::showpoint << 34.1 << "\n"; // prints: 34.100 std::cout << std::noshowpoint << 34.1 << "\n\n"; // prints: 34.1 return 0; }
#include <limits>.std::numeric_limits<datatype>| Call | Returns |
|---|---|
std::numeric_limits<T>::max() | The largest value the type can hold. |
std::numeric_limits<T>::min() | The smallest value for integers, or the smallest safe positive value for decimals. |
std::numeric_limits<T>::lowest() | The actual most negative value the type can hold. |
For integers, min() and lowest() give the exact same result. For decimal types they don't: min() gives the smallest full-precision positive number, not the most negative one, lowest() gives the actual most negative value, and denorm_min() gives the absolute smallest positive number possible, a subnormal value. In practice, stick to max() and lowest() for decimal types.
#include <iostream> #include <limits> int main() { std::cout << "short: " << std::numeric_limits<short>::min() << " to " << std::numeric_limits<short>::max() << std::endl; // prints: -32768 to 32767 std::cout << "int: " << std::numeric_limits<int>::min() << " to " << std::numeric_limits<int>::max() << std::endl; // prints: -2147483648 to 2147483647 std::cout << "unsigned int: " << std::numeric_limits<unsigned int>::min() << " to " << std::numeric_limits<unsigned int>::max() << std::endl; // prints: 0 to 4294967295 std::cout << "long: " << std::numeric_limits<long>::min() << " to " << std::numeric_limits<long>::max() << std::endl; // prints: -2147483648 to 2147483647 (or larger on 64-bit) std::cout << "float: " << std::numeric_limits<float>::lowest() << " to " << std::numeric_limits<float>::max() << std::endl; // prints: -3.40282e+38 to 3.40282e+38 std::cout << "double: " << std::numeric_limits<double>::lowest() << " to " << std::numeric_limits<double>::max() << std::endl; // prints: -1.79769e+308 to 1.79769e+308 return 0; }
Requires #include <cmath>.
| Function | What It Does | Example |
|---|---|---|
std::round(x) | Rounds to the nearest integer. First digit after the decimal ≥ 5 rounds up, ≤ 4 rounds down. | round(3.5) = 4, round(3.4) = 3 |
std::floor(x) | Always rounds down to the lower integer. | floor(3.7) = 3 |
std::ceil(x) | Always rounds up to the upper integer. | ceil(3.1) = 4 |
std::abs(x) | Returns the absolute, positive value. | abs(-5) = 5 |
std::pow(x, y) | Returns x raised to the power y. | pow(2, 3) = 8 |
std::exp(x) | Returns e, Euler's constant (2.71828), raised to the power x. | exp(4) = 54.598 |
std::log(x) | Natural logarithm, base e. The inverse of exp(). | log(54.59) = 4 |
std::log10(x) | Logarithm with base 10. | log10(10000) = 4 |
std::sqrt(x) | Returns the square root. | sqrt(49) = 7 |
std::cos(x) | Cosine of x, in radians. | cos(0) = 1 |
std::sin(x) | Sine of x, in radians. | sin(0) = 0 |
std::tan(x) | Tangent of x, in radians. | tan(45) = 1.619 |
#include <iostream> #include <cmath> int main() { std::cout << "round(3.5) = " << std::round(3.5) << std::endl; // prints: 4 std::cout << "round(3.4) = " << std::round(3.4) << std::endl; // prints: 3 std::cout << "floor(3.7) = " << std::floor(3.7) << std::endl; // prints: 3 std::cout << "ceil(3.1) = " << std::ceil(3.1) << std::endl; // prints: 4 std::cout << "abs(-5) = " << std::abs(-5) << std::endl; // prints: 5 std::cout << "pow(2, 3) = " << std::pow(2, 3) << std::endl; // prints: 8 std::cout << "exp(4) = " << std::exp(4) << std::endl; // prints: 54.5982 std::cout << "log(54.59) = " << std::log(54.59) << std::endl; // prints: ~4 std::cout << "log10(10000) = " << std::log10(10000) << std::endl; // prints: 4 std::cout << "sqrt(49) = " << std::sqrt(49) << std::endl; // prints: 7 std::cout << "cos(0) = " << std::cos(0) << std::endl; // prints: 1 std::cout << "sin(0) = " << std::sin(0) << std::endl; // prints: 0 std::cout << "tan(45) = " << std::tan(45) << std::endl; // prints: 1.6198 (radians) return 0; }
int, usually less than 4 bytes, do not directly support arithmetic operators.int. This is called integer promotion.char (1 byte) and short (2 bytes).int, never char or short.int is the smallest type the CPU handles efficiently for arithmetic.auto to store the result safely and sidestep accidental narrowing or overflow.If you store the result of char + char back into a char, you may silently lose data, because the actual result of that addition is an int. Using auto instead sidesteps the whole problem, since it just stores whatever type the promotion actually produced.
#include <iostream> int main() { short short1 = 10; short short2 = 20; auto shortsum = short1 + short2; // promoted to int before addition, result is int std::cout << "sizeof(short1) = " << sizeof(short1) << std::endl; // prints: 2 std::cout << "sizeof(short2) = " << sizeof(short2) << std::endl; // prints: 2 std::cout << "sizeof(shortsum) = " << sizeof(shortsum) << std::endl; // prints: 4 (int!) std::cout << "shortsum = " << shortsum << std::endl; // prints: 30 char char1 = 5; char char2 = 10; auto charsum = char1 + char2; // promoted to int before addition, result is int std::cout << "\nsizeof(char1) = " << sizeof(char1) << std::endl; // prints: 1 std::cout << "sizeof(char2) = " << sizeof(char2) << std::endl; // prints: 1 std::cout << "sizeof(charsum) = " << sizeof(charsum) << std::endl; // prints: 4 (int!) std::cout << "charsum = " << charsum << std::endl; // prints: 15 return 0; }
That's the full set of operators, every output manipulator worth knowing, how to check a type's real limits, the math library, and the one promotion rule that silently rewrites the type of your arithmetic. Next up, arrays.