2 Variables and Data Types

A practical progression through C++ variables, initialization, built-in types, constants, operators, conversions, and clear expression evaluation.

Declaring and Using Variables

A C++ is a named, typed object that stores a value while a program runs. A declaration introduces the ’s name and type, while an initializer supplies its first value.

Use meaningful identifiers that describe the stored value. C++ identifiers may contain letters, digits, and underscores, but they cannot begin with a digit or be reserved keywords. C++ is case-sensitive, so score, Score, and SCORE name different objects.

Prefer at the point of declaration. Examples include int total{};, which value-initializes total to zero, int limit{100};, double price{19.99};, char grade{'A'};, and bool is_ready{true};.

An uninitialized local may contain an indeterminate value. Reading such a value can produce incorrect results or undefined behavior.

creates an object and gives it its first value. replaces the value of an object that already exists. For example, int width{10}; initializes width, and width = 25; later assigns a new value to it. Remember that = performs , while == tests equality.

Takeaway: Give variables meaningful names, initialize them promptly, and distinguish creating an object from changing its value.

Choosing Built-in Data Types

The type of an object determines the kind of value it can represent and the operations that make sense for it. A is supplied by the C++ language rather than defined by the programmer.

  • bool represents true or false. In a condition, a zero-valued number is treated as false and a nonzero number is treated as true.

  • Character types such as char store character values written with single quotes, such as char initial{'M'};. Character types are also integral types, so they can participate in arithmetic.

  • Integral types such as short, int, long, and long long represent whole numbers. Signed forms can represent negative values; unsigned forms represent only nonnegative values.

  • Floating-point types such as float, double, and long double represent approximations of real-number values.

  • void indicates no value, commonly for a function that does not return a value.

  • std::nullptr_t is the type of the nullptr literal.

The exact size and range of many arithmetic types depend on the implementation and target platform. Unsigned arithmetic requires care: subtracting a larger value from a smaller one does not produce a negative result; it wraps according to the rules for that unsigned type. Prefer signed integers unless a nonnegative range or bit-level representation is specifically required.

Floating-point values may not represent decimal numbers exactly. As a result, exact equality comparisons involving calculated values such as 0.1 can produce surprising results.

Takeaway: Choose a type that expresses the intended values, and account for implementation-dependent ranges, unsigned behavior, and floating-point approximation.

Constants and Immutability

A is a value that should not change after . Apply const when an object must remain unmodifiable, as in const double tax_rate{0.0725}; or const int maximum_attempts{3};. Attempting to assign a new value to a const object is an error.

A typed participates in C++ type checking, unlike a preprocessor macro. For example, const int days_in_week{7}; communicates both the value and its type.

Use constexpr when a value is required or intended to be computable at compile time. For example, constexpr int seconds_per_minute{60};, constexpr int minutes_per_hour{60};, and constexpr int seconds_per_hour{seconds_per_minute * minutes_per_hour}; express compile-time constants.

A useful guideline is to make an object const by default when it should not be modified, and to use constexpr for values suitable for compile-time evaluation.

Takeaway: Express immutability in the type system: use const for read-only objects and constexpr for compile-time constants.

Operators and Conditions

Operators let a program update values, calculate results, and form conditions. The simple operator stores the value on the right in the object on the left. For example, int points{10}; followed by points = 25; changes the stored value.

Compound combines an operation with . Common forms include x += y, x -= y, x *= y, x /= y, and x %= y. For example, int score{80}; score += 5; changes the score to 85, and score /= 5; then changes it to 17.

Increment and decrement operators add or subtract one. Prefix forms such as ++count modify the object before producing its value. Postfix forms such as count++ produce the old value before modifying the object. When the resulting value is not needed, the prefix form is often clearer.

The arithmetic operators are addition, subtraction, multiplication, division, and remainder. The remainder operator applies to integral operands. Do not divide by zero: division by zero is not a valid arithmetic operation and can result in undefined behavior or a runtime failure.

Comparison operators produce Boolean results: ==, !=, <, >, <=, and >=. Logical operators combine or invert conditions: && means logical AND, || means logical OR, and ! means logical NOT.

makes conditions safer when one test guards another. In if (denominator != 0 && numerator / denominator > 2), the division is evaluated only when denominator is not zero. Similarly, the right side of A || B is evaluated only when A is false.

Takeaway: Use and compound deliberately, distinguish arithmetic from comparison, and use logical short-circuiting to guard operations when appropriate.

Conversions and Evaluation

An combines values, variables, operators, and function calls to produce a result. Expressions have a type and a value, and C++ may convert operands so that an operation is well-formed.

A produces a value of one type from a value of another type. Some conversions are implicit. For example, in int count{3}; double average{count + 0.5};, the integer is converted to double before the addition. Conversions to a narrower or less precise type can lose information, as in double measurement{9.75}; int truncated{measurement};, where the fractional part is discarded.

Use when an explicit conversion makes the intent clearer. In int total{7}; int people{2}; double per_person{<double>(total) / people};, converting total to double ensures that the division produces 3.5 rather than the integer-division result 3.

Brace helps detect narrowing conversions. int value1{3.14}; is rejected because it would narrow the value, whereas int value2 = 3.14; compiles but truncates the value to 3. An explicit cast does not make a potentially unsafe conversion safe; it states that the programmer accepts the conversion.

Operator precedence determines grouping. Multiplication, division, and remainder bind more tightly than addition and subtraction, so 2 + 3 * 4 produces 14. Parentheses change the grouping, so (2 + 3) * 4 produces 20. Use parentheses whenever they improve clarity, even when precedence already gives the intended result.

Avoid expressions that modify the same object multiple times when the order of those modifications is unclear. Separate the operations into statements, such as storing the current value in one statement and incrementing the index in the next.

Takeaway: Understand operand types, make important conversions explicit, use parentheses to communicate grouping, and favor clear statements over compressed expressions with interacting side effects.

Putting the Ideas Together

A small program can combine typed variables, constants, arithmetic, comparison, logical operators, compound , and conversion. One example uses constexpr double sales_tax{0.08};, const int quantity{3};, and mutable variables such as double unit_price{12.50};.

The calculation can proceed in stages: subtotal is initialized from the unit price and quantity, tax is initialized from the subtotal and tax rate, and total is initialized from the subtotal plus the tax. Multiplying a double by an int performs the needed implicit conversion for the floating-point calculation.

A condition such as total >= 40.0 && quantity >= 3 produces a Boolean result. If that result is true, compound such as total *= 0.90; updates the total.

A reliable review process is to check each ’s type and , identify every conversion, verify whether a division is integer or floating-point, inspect conditions for short-circuit guards, and add parentheses or separate statements wherever evaluation could be misunderstood.

Final checklist:

  • Is every local initialized before it is read?

  • Should an object be const or constexpr?

  • Could a conversion lose information?

  • Are arithmetic and comparison operators being used intentionally?

  • Could discard a needed fractional part?

  • Are potentially unsafe operations protected by a clear condition?

  • Are expressions readable and free from interacting side effects?

Takeaway: Correct C++ expressions depend on more than their visible operators: types, , conversions, grouping, and evaluation behavior all contribute to the result.