SovranCode
Modern C++ Lesson 07
Course contents50 available · 0 planned

Get a program running

01 · C++ Introduction: What Is C++?02 · How to Install a C++ Compiler and Set Up Your Editor03 · C++ Hello World: Your First Program Explained04 · How to Compile and Run C++ Programs05 · C++ Debugging: Warnings and Breakpoints

Work with values and input

06 · C++ Variables: Initialization and Scope07 · C++ Data Types: int, double and Type Conversion08 · C++ const, constexpr and auto Explained09 · C++ Operators: Arithmetic, Comparison and Logic10 · C++ User Input: cin, getline and Validation

Control flow and functions

11 · C++ Conditions: if, else if and else12 · C++ Switch Statement: Cases, break and default13 · C++ For Loop: Syntax and Examples14 · C++ While and Do-While Loops: Examples15 · C++ Functions: Parameters and Return Values

Strings and sequences

16 · C++ Strings: std::string with Examples17 · C++ Vector: std::vector with Examples18 · C++ Arrays: std::array and Bounds Checking19 · C++ Range-Based For Loop and Iterators20 · C++ Vector Practice: Build a Data Summary

Model data with classes

21 · C++ Structs and enum class Explained22 · C++ Classes and Objects: Encapsulation23 · C++ Constructors and Member Initialization24 · C++ Const Member Functions and Composition25 · C++ Copying Objects and the Rule of Zero

Lifetime and resource ownership

26 · C++ Object Lifetime, Destructors and RAII27 · C++ Pointers and References: nullptr and Borrowing28 · C++ unique_ptr: Smart Pointers and Ownership29 · C++ Move Semantics: std::move vs Copying30 · C++ string_view and span: Avoid Dangling Views

Containers and algorithms

31 · C++ map vs unordered_map: Lookup and Examples32 · C++ set, queue and stack: When to Use Each33 · C++ Lambda Expressions and STL Algorithms34 · C++ sort and binary_search: Rules and Complexity35 · C++20 Ranges: Views, filter and transform

Errors, files, and interfaces

36 · C++ optional and variant Explained37 · C++ Exceptions: try, catch and Safe Cleanup38 · C++ File Handling: Read and Write Text Files39 · C++ Input Parsing and Data Validation40 · C++ Polymorphism: Virtual Functions and Interfaces

Generic programming and quality

41 · C++ Templates: Function and Class Examples42 · C++20 Concepts and Template Constraints43 · C++ Unit Testing: Normal and Boundary Cases44 · C++ Sanitizers: Find Memory and Undefined Behavior Bugs45 · C++ Performance: Benchmark Before Optimizing

Build and deliver a complete application

46 · C++ Header Files and Translation Units47 · C++ CMake Tutorial: Build an Executable48 · C++ Dependencies and CTest: Automated Tests49 · C++ Multithreading: Threads and Data Races50 · C++ Command-Line Applications: Help and Release Checks
Modern C++50 available · 0 planned

Get a program running

01 · C++ Introduction: What Is C++?02 · How to Install a C++ Compiler and Set Up Your Editor03 · C++ Hello World: Your First Program Explained04 · How to Compile and Run C++ Programs05 · C++ Debugging: Warnings and Breakpoints

Work with values and input

06 · C++ Variables: Initialization and Scope07 · C++ Data Types: int, double and Type Conversion08 · C++ const, constexpr and auto Explained09 · C++ Operators: Arithmetic, Comparison and Logic10 · C++ User Input: cin, getline and Validation

Control flow and functions

11 · C++ Conditions: if, else if and else12 · C++ Switch Statement: Cases, break and default13 · C++ For Loop: Syntax and Examples14 · C++ While and Do-While Loops: Examples15 · C++ Functions: Parameters and Return Values

Strings and sequences

16 · C++ Strings: std::string with Examples17 · C++ Vector: std::vector with Examples18 · C++ Arrays: std::array and Bounds Checking19 · C++ Range-Based For Loop and Iterators20 · C++ Vector Practice: Build a Data Summary

Model data with classes

21 · C++ Structs and enum class Explained22 · C++ Classes and Objects: Encapsulation23 · C++ Constructors and Member Initialization24 · C++ Const Member Functions and Composition25 · C++ Copying Objects and the Rule of Zero

Lifetime and resource ownership

26 · C++ Object Lifetime, Destructors and RAII27 · C++ Pointers and References: nullptr and Borrowing28 · C++ unique_ptr: Smart Pointers and Ownership29 · C++ Move Semantics: std::move vs Copying30 · C++ string_view and span: Avoid Dangling Views

Containers and algorithms

31 · C++ map vs unordered_map: Lookup and Examples32 · C++ set, queue and stack: When to Use Each33 · C++ Lambda Expressions and STL Algorithms34 · C++ sort and binary_search: Rules and Complexity35 · C++20 Ranges: Views, filter and transform

Errors, files, and interfaces

36 · C++ optional and variant Explained37 · C++ Exceptions: try, catch and Safe Cleanup38 · C++ File Handling: Read and Write Text Files39 · C++ Input Parsing and Data Validation40 · C++ Polymorphism: Virtual Functions and Interfaces

Generic programming and quality

41 · C++ Templates: Function and Class Examples42 · C++20 Concepts and Template Constraints43 · C++ Unit Testing: Normal and Boundary Cases44 · C++ Sanitizers: Find Memory and Undefined Behavior Bugs45 · C++ Performance: Benchmark Before Optimizing

Build and deliver a complete application

46 · C++ Header Files and Translation Units47 · C++ CMake Tutorial: Build an Executable48 · C++ Dependencies and CTest: Automated Tests49 · C++ Multithreading: Threads and Data Races50 · C++ Command-Line Applications: Help and Release Checks
PREVIOUS LESSONC++ Variables: Initialization and Scope
NEXT LESSONC++ const, constexpr and auto Explained
C++ foundations · Lesson 07 About 50 min with practice

C++ Data Types: int, double and Type Conversion

Choose C++ int, double, bool and char deliberately. Fix integer division, inspect numeric limits, understand narrowing and floating-point approximation, and calculate a meaningful average.

Before you begin

Complete variables and initialization. Use the compiler-backed editor when available, or your local C++20 compiler, for double, casts, stream formatting and numeric limits.

What you will learn

  • Match a type to the kind of value it represents.
  • Predict integer division before a result is assigned.
  • Convert an operand deliberately rather than casting a truncated result.
  • Explain range, narrowing and floating-point approximation.
  • Separate storage, calculation and display precision.

Choose the meaning before choosing the type

A type tells C++ how a value can be represented and which operations make sense. It does not supply the complete meaning of your data. A count of books and a temperature can both be numbers, but one usually needs whole units and the other may need a fractional part. Write the unit and permitted range beside the requirement before choosing a declaration. This prevents a technically valid calculation from answering the wrong question.

Use int for modest whole-number examples that may involve negative values. Use double for approximate real-number measurements and ratios. bool represents true or false, such as whether a reading passed validation. char represents one character code unit, not arbitrary human text. std::string is a library type for a sequence of characters. Quoting a digit as '7' creates a character; writing 7 creates an integer literal. Those values are not interchangeable descriptions of the same object.

The spelling of the initializer matters. In these examples 7 is an int literal and 7.0 is a double literal. A suffix can select another type, but adding suffixes without understanding them only hides the conversion path. Keep beginner examples explicit and small. For user-facing text, use a string rather than hoping a single char can represent a complete accented symbol or emoji. Text encoding deserves its own treatment beyond this numeric lesson.

Seven divided by two as integers produces three before assignment to double; converting seven to double before division produces three point five. A display-formatting step changes presentation, not the arithmetic already performed.
The operands decide the arithmetic. The destination type cannot restore a fraction already discarded.

Why double result = 7 / 2 still stores 3

Both operands in 7 / 2 are integers, so this operation uses integer division. Its result is 3: the fractional part is discarded. Assigning that result to double later converts 3 into a floating-point value; it cannot recover the lost half. Read the expression from its operands toward its destination. The declaration on the left does not instruct every operation on the right to become floating-point arithmetic.

Convert an operand before the division when the required answer is a ratio. static_cast<double>(total) / count makes the conversion visible. With the small values here, converting total is exact, and the mixed operation converts count to double as well. Casting total / count instead is too late. Replacing a cast with a floating-point literal is suitable when the denominator really is a fixed literal, but named counts should keep their meaning and not become unexplained constants.

Integer division truncates toward zero, not toward negative infinity. For example, -7 / 2 produces -3. The remainder operator belongs to integer arithmetic; -7 % 2 is -1 for this case. Avoid treating remainder as a universal mathematical modulo operation for negative values. Also never divide or take remainder by zero. Keep the denominator nonzero by design, or check it before computing; the conditions lesson explains the branch that protects the operation.

C++ PRACTICE RUNNER

Compare a late conversion with an early conversion

Predict both averages. fixed and setprecision format the printed double values; they do not repair the first calculation.

#include <iostream>
#include <iomanip>
int main() {
    const int total{7};
    const int count{2};
    const double late{static_cast<double>(total / count)};
    const double early{static_cast<double>(total) / count};
    std::cout << std::fixed << std::setprecision(2);
    std::cout << "Late: " << late << '\n';
    std::cout << "Early: " << early << '\n';
    return 0;
}
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Compare with the starter's expected output
Late: 3.00
Early: 3.50

After editing inputs, calculate a new prediction; this reference describes only the starter.

Range and signedness are part of the contract

Do not assume int always occupies exactly four bytes or that every platform has identical numeric limits. The standard guarantees minimum capabilities; your implementation provides actual limits. Include limits and inspect std::numeric_limits<int>::lowest() and max() for your chosen target. Those observations describe that build environment, not an eternal property of all C++ systems. sizeof reports storage in C++ bytes, whose definition is not a promise that every byte has eight bits.

Unsigned types represent nonnegative values and use modular arithmetic for their range. That does not make them a general-purpose solution to invalid negative input. A negative value converted to an unsigned type can become a large positive value. Mixing signed and unsigned operands can also change a comparison's meaning through conversions. For these small instructional counts, retain int and validate the domain rather than adding unsigned as a decoration.

Signed integer overflow is not a reliable wrapping calculation. Do not run an overflowing expression and use the observed result as a rule. A larger type can help only if its range is actually sufficient for every intermediate expression. A final destination with extra range does not rescue an earlier overflowing multiplication. Later validation and testing lessons develop checked calculations; here constrain inputs and explain the bounds you rely on.

Braces reveal some unwanted conversions

Brace initialization rejects certain narrowing conversions. int sessions{2.5} therefore fails in C++20 instead of silently discarding a fraction. This is a valuable diagnostic, not an obstacle to remove automatically. Ask whether sessions is truly a whole count, whether the initializer is wrong, or whether the model needs a fractional type. Different answers require different repairs. A cast documents an explicit conversion but does not prove the conversion is appropriate or safe.

Converting a floating-point value to an integer discards the fractional part toward zero when the result is representable. It is not ordinary rounding. A conversion outside the destination's representable range is unsafe. Do not use a cast as an input-validation strategy. Check the requirement and range before converting, and keep the original value if the report still needs its fraction. This distinction becomes especially important when parsing measurements supplied by a user.

C++ PRACTICE RUNNER

Repair a narrowing declaration

Intentional compile failure. Choose int sessions{2} for two complete sessions, or double sessions{2.5} if fractional sessions are part of the requirement. Explain the model before selecting the repair.

int main() { int sessions{2.5}; return sessions; }
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Display precision is not numerical exactness

Floating-point types have finite precision. On common binary implementations, many decimal fractions are approximations. A short printed value can hide that approximation because stream formatting rounds the display. Printing two decimal places does not change the stored object or establish that two computed values are exactly equal. Avoid a universal tolerance constant: a useful comparison depends on the scale, acceptable error and kind of measurement being modeled.

Money needs a deliberately specified representation and rounding policy. For a small whole-cent example, storing 1250 cents as an integer avoids introducing an approximate decimal dollar value. That is not a complete accounting solution: currency, overflow, fractional cents, tax rules and rounding still need explicit decisions. Use double for our average lesson because a ratio is intended; do not generalize that choice to every financial quantity simply because its output contains a decimal point.

To review a numeric expression, write four answers: the type of each operand, the operation performed, the range of the intermediate result, and the final display format. This separates a storage mistake from a formula mistake and a presentation mistake. Change total from seven to eight and then to zero while leaving count at two. Predict each result first. An empty data set is a separate state, not an invitation to divide by a zero count.

LOCAL TERMINAL COMMANDS

Build and run the local examples

Save one complete example or lab solution as main.cpp. Choose your installed toolchain; run only after a successful build. Input examples wait for text in your terminal. The browser teaching interpreter does not support these full-language features.

macOS / Clang:
clang++ -std=c++20 -Wall -Wextra -Wpedantic main.cpp -o lesson
./lesson

Linux / GCC:
g++ -std=c++20 -Wall -Wextra -Wpedantic main.cpp -o lesson
./lesson

Windows Developer Command Prompt / MSVC:
cl /std:c++20 /EHsc /W4 main.cpp /Fe:lesson.exe
lesson.exe
APPLY THE CONCEPT

Independent lab

Report the average pages read across four sessions without losing the fractional part. Explain why the count cannot be zero.

Acceptance checklist

  • Initialize totalPages to 11 and sessionCount to 4 as int values.
  • Compute a double average by converting before division.
  • Print Average pages: 2.75 with exactly two decimal places.
  • Change totalPages to 12 and predict 3.00.
  • Explain why an empty session set needs a separate decision, not division by zero.
Need a hint?
  1. Cast an operand, not the already computed quotient.
  2. Include iomanip for fixed and setprecision.
  3. Keep the unit pages per session in your explanation.
C++ PRACTICE RUNNER

Write and run your lab

Build your own solution before revealing the reference. Use the input field for normal, boundary and invalid cases; this runner executes your program but does not grade it.

#include <iostream>
#include <string>
#include <sstream>
#include <limits>

int main() {
    // Implement the acceptance checklist above.
    return 0;
}

TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Your lab evidence and notes

Record predictions, actual output, commands and the cause of each repair. Code is plain text: this scratchpad does not execute or grade C++.

Loading local notes…

Review your acceptance checklist and quiz explanations before marking this lesson complete. This is self-review, not a grade or certification.

Reveal the explained lab solution
C++ PRACTICE RUNNER

Reference lab solution

Compare the reference with your own reasoning. Running this solution does not grade or complete the lesson.

#include <iostream>
#include <iomanip>
int main() {
    const int totalPages{11};
    const int sessionCount{4};
    const double average{static_cast<double>(totalPages) / sessionCount};
    std::cout << std::fixed << std::setprecision(2);
    std::cout << "Average pages: " << average << '\n';
    return 0;
}
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Expected output

Average pages: 2.75

The total and count remain whole-number facts; only the ratio needs a fractional representation.

Converting totalPages before division preserves the intended fraction. Converting 11 / 4 afterward would store 2 instead.

The lab fixes sessionCount at four. A generalized program must reject or separately report zero sessions before computing an average.

Review before moving on

Explain the lesson's objectives in your own words, compare your lab evidence with the acceptance checklist, and keep the first failing case alongside your repair. Completing a page is not proof that every C++ feature or input is supported.

  • Match a type to the kind of value it represents.
  • Predict integer division before a result is assigned.
  • Convert an operand deliberately rather than casting a truncated result.
  • Explain range, narrowing and floating-point approximation.
  • Separate storage, calculation and display precision.

References and further reading

Original examples and exercises accompany these primary references. Tool-specific diagnostics and support depend on your installed version.

  • C++ draft: multiplicative operators
  • C++ draft: numeric limits
  • C++ draft: list initialization
KNOWLEDGE CHECK

Check your understanding

Answer all five questions, then review the explanations. Answers are not saved or synced; completion is a separate self-review choice.

01What is the value of double x = 7 / 2?
02Which expression preserves the fractional ratio of two small int values?
03What does setprecision with fixed change?
04Why does int count{2.5} fail?
05Which is the best range reference for your int implementation?
PREVIOUS LESSONC++ Variables: Initialization and Scope
NEXT LESSONC++ const, constexpr and auto Explained
ON THIS PAGELearning objectivesChoose the meaning before choosing the typeWhy double result = 7 / 2 still stores 3Range and signedness are part of the contractBraces reveal some unwanted conversionsDisplay precision is not numerical exactnessIndependent labReviewKnowledge checkReferences
Course overview