Chapter 02 · Reps

Asking Questions and Doing Them Again — Reps

← Back to Chapter 2

Chapter 2 — Reps

Conditioning, not grading. Eighteen of them this week, because Week 2 is a double-width week — half of them are conditionals, half are loops, and the last few are both at once. Do them in order, before you open Project 2.

Ground rules:

  1. Type every line yourself. No copy-paste, no autocomplete.
  2. Compile with -Wall -Wextra and run after every single rep.
  3. Read the first error before reaching for anything else. §2.18 has the real text of nearly every error you will hit this week.
  4. AI off. This is the week your hands learn loops, and hands do not learn from watching.

About the expected output

Every rep below ships with the exact output the finished program prints, because there is nobody in the room to tell you whether you got it right. Every block was produced by actually running the solution — nothing here is predicted.

Two things to know before you compare:

  • Prompts and answers share a line. These transcripts were produced by piping input into the program, so the answer lands on the same line as the prompt. When you type by hand in OnlineGDB, your typed number appears after the prompt and then the rest of the output follows. Everything after the prompt is identical.
  • Trailing spaces are real. When a program prints i << " ", the last item on the line is followed by a space. That space is in the expected output. It is not a typo.

If your output differs by a word, a space, or a digit, you have a real difference. Find it before moving on.


Reps 1–6: Asking One Question

Rep 1 — Even or Odd

Ask the user for an integer. Print N is even. or N is odd. using a single if/else and the modulo operator (n % 2 == 0). Braces on both branches (§2.4).

Run it four times, feeding 0, 1, -3, 100.

Expected output — four separate runs, in that order:

Enter an integer: 0 is even.
Enter an integer: 1 is odd.
Enter an integer: -3 is odd.
Enter an integer: 100 is even.

Now the trap. Change the test to n % 2 == 1 and flip the two branches so it still reads correctly. Feed it -3 again:

Enter an integer: -3 is even.

Wrong. In C++, -3 % 2 is -1, not 1, so -1 == 1 is false and the negative odd number falls into the else. Test against == 0, not == 1. Put your program back the way it was.


Rep 2 — Grade Cascade

Ask for an integer score and print a letter grade with an if/else if/else cascade at the standard 90/80/70/60 thresholds (§2.4). Run it five times: 100, 89, 70, 59, 42.

Expected output — five runs, in that order:

Enter a score (0-100): Grade: A
Enter a score (0-100): Grade: B
Enter a score (0-100): Grade: C
Enter a score (0-100): Grade: F
Enter a score (0-100): Grade: F

Now write the cascade backwards>= 60 first, then >= 70, then >= 80, then >= 90 — and feed it 95:

Enter a score (0-100): Grade: D

A 95 became a D, and the compiler said nothing. The first true branch wins, and 95 >= 60 is the first thing you asked. Fix the order and move on; you have now met the single most common cascade bug.


Rep 3 — Six Comparisons

Read two integers into a and b, then two words into two string variables first and second. Turn on boolalpha and print all six relational comparisons on the integers (§2.2), then first < second and first == second.

Run A: feed 7 10, then apple banana.

Expected output:

Enter two integers: Enter two words: a == b : false
a != b : true
a <  b : true
a <= b : true
a >  b : false
a >= b : false
first <  second : true
first == second : false

Run B: feed 42 42, then Zebra apple.

Expected output:

Enter two integers: Enter two words: a == b : true
a != b : false
a <  b : false
a <= b : true
a >  b : false
a >= b : true
first <  second : true
first == second : false

Look hard at the last two lines of Run B. "Zebra" < "apple" is true, because std::string compares by character code and 'Z' is 90 while 'a' is 97. That is not alphabetical order, and it is the reason case-insensitive comparison has to wait for Chapter 3.


Rep 4 — Close Enough

No input for this one. Write a program that declares const double EPSILON = 0.0001; and three pairs of doubles: a = 0.1 + 0.2 against b = 0.3; c = 1.0 - 0.9 against d = 0.1; e = 4.0 / 2.0 against f = 2.0. For each pair print the difference, the == result, and whether abs(difference) < EPSILON. You need #include <cmath> (§2.3).

Expected output:

a - b = 5.55112e-17
(a == b) = false
close enough = true

c - d = -2.77556e-17
(c == d) = false
close enough = true

e - f = 0
(e == f) = true
close enough = true

Three lessons in nine lines. Two doubles that should be equal are not. The error can be negative as easily as positive. And the third pair shows that == on doubles is not always wrong — 4.0 / 2.0 is exact, so it works. That is precisely why the bug is so hard to catch by testing: it passes until it doesn’t. Use close-enough anyway, every time.


Rep 5 — Login Gate

Ask for an age (int) and a verified answer (yes/no, read as a string). Build two named booleans — old_enough and is_verified — and print exactly one of four messages: a welcome, or a rejection that says which requirement failed. You need && and ! (§2.5), and positively-named booleans (§2.9).

Run it four times: 20 yes, 16 yes, 20 no, 16 no.

Expected output — four runs, in that order:

Age: Verified (yes/no): Welcome.
Age: Verified (yes/no): Denied: under 18.
Age: Verified (yes/no): Denied: account is not verified.
Age: Verified (yes/no): Denied: under 18 and not verified.

The both-failed case has to come before the single-failure cases in the cascade, or it never fires. Order again.


Rep 6 — Guard First

Short-circuit evaluation is invisible, so this rep makes it visible. Read a numerator and a denominator. Declare int probe = 0;. Then write:

if ((denominator != 0) && ((probe = numerator / denominator) > 5)) {

…with an else if (denominator == 0) branch and a final else. After the whole thing, print probe.

Run it three times: 100 3, 100 0, 100 25.

Expected output — three runs, in that order:

Numerator: Denominator: Quotient is greater than 5.
probe = 33
Numerator: Denominator: Cannot divide by zero.
probe = 0
Numerator: Denominator: Quotient is 5 or less.
probe = 4

probe = 0 on the middle run is the whole point. The right-hand side of the && never ran — which is the only reason your program did not try to divide 100 by zero. That is short-circuit evaluation, and it is load-bearing, not cosmetic.

Do not flip the two halves of that && to see what happens. Dividing by zero is undefined behavior: some machines kill the program, some hand you nonsense, and “it worked on mine” proves nothing. Guard first, then use (§2.5) — that is a rule, not a preference.


Reps 7–9: Choosing Among Many

Rep 7 — Day Name, Twice

Ask for an integer 1–7 and print the day of the week (1 = Monday, 7 = Sunday). Write it first with if/else if/else, saved as day_if.cpp. Then write a second program, day_switch.cpp, that does the same job with a switch and a default (§2.7).

Run both, feeding 1, 3, 7, 9.

Expected output — four runs, in that order. Both programs must print exactly this:

Day number (1-7): Monday
Day number (1-7): Wednesday
Day number (1-7): Sunday
Day number (1-7): Not a day of the week.

Two independent routes to the same answer is how you grade yourself when nobody is around (§2.13). If the two files disagree on any input, one of them is wrong and you now know exactly where to look.

Then notice your own reaction: which one would you rather add an eighth case to? There is no right answer — switch is built for dispatching on one integer value, and this is that shape.


Rep 8 — Grouped Cases

Ask for a single char naming a class of physical constant: G gravitational, C cosmological, E electromagnetic, W weak nuclear, S strong nuclear. Use a switch with case 'W': and case 'S': stacked to share one body — intentional fall-through, commented — plus a default (§2.7).

Run it five times: G, C, W, S, Q.

Expected output — five runs, in that order:

Constant class (G/C/E/W/S): Gravitational force.
Constant class (G/C/E/W/S): Cosmological constant.
Constant class (G/C/E/W/S): Nuclear force.
Constant class (G/C/E/W/S): Nuclear force.
Constant class (G/C/E/W/S): Unknown class.

Now delete the break; at the end of case 'G': and feed it G again:

Constant class (G/C/E/W/S): Gravitational force.
Cosmological constant.

Two cases ran. That is what a missing break does. With -Wall -Wextra, g++ 14 warns first (file names, line numbers, and column markers stripped; wording varies slightly by compiler version):

warning: this statement may fall through [-Wimplicit-fallthrough=]
            cout << "Gravitational force." << endl;
note: here
        case 'C':

Drop -Wextra and that warning disappears completely. Some compilers never emit it at all — the same file compiled silently and cleanly under Apple clang. Assume the compiler will not save you here (§2.18). Put the break back.


Rep 9 — Two Levels Deep

Ask for the user’s age. If they are under 18, ask a second question — “Do you have parental permission? (yes/no)” — and print Welcome with permission. or Access denied.. If they are 18 or over, ask a different second question — “Have you read the terms? (yes/no)” — and print Welcome. or Please read the terms first.. Genuine two-level nesting (§2.6): the second question exists only because of the first answer.

Run it four times: 16 yes, 16 no, 22 yes, 22 no.

Expected output — four runs, in that order:

Age: Do you have parental permission? (yes/no): Welcome with permission.
Age: Do you have parental permission? (yes/no): Access denied.
Age: Have you read the terms? (yes/no): Welcome.
Age: Have you read the terms? (yes/no): Please read the terms first.

Now try to flatten it into a single if/else if chain with &&. You will find you cannot, cleanly — the program does not even know which question to ask until it has the age. That is the tell: nest when the problem is nested (§2.6). Project 2 has exactly this shape.


Reps 10–11: Break It On Purpose

Rep 10 — Trace First, Run Second

Do not type this in yet. Get paper. Write down, line by line, what you think it prints — all five lines, in order — before you touch a keyboard. This is the highest-yield drill in the chapter and the exact skill the Week 4 Part A exam tests.

int x = 5;
int y = 10;

if (x = 3) {
    cout << "A" << endl;
} else {
    cout << "B" << endl;
}
cout << "x is " << x << endl;

if (y == 10) {
    cout << "C" << endl;
}

if ((x > 0) && ((y / x) > 3)) {
    cout << "D" << endl;
} else {
    cout << "E" << endl;
}
cout << "y / x is " << (y / x) << endl;

Written it down? Now type it into a real program and run it.

Expected output:

A
x is 3
C
E
y / x is 3

And the compiler said this on the way through (g++ 14, -Wall -Wextra, prefixes stripped):

warning: suggest parentheses around assignment used as truth value [-Wparentheses]
    if (x = 3) {
        ~~^~~

Three traps in one program. if (x = 3) assigns 3 to x, evaluates to 3, and 3 is non-zero, so branch A always runs — and x is now silently 3 (§2.8). Then integer division: 10 / 3 is 3, and 3 > 3 is false, so E prints, not D. If your paper matched all five lines, §2.8 has landed. If it did not, the line where your trace first diverged is the concept you owe another pass.


Rep 11 — Five Broken Conditionals

Break working code on purpose, one change at a time, compile, read the message, fix it. This is how you learn to read compiler output when there is nobody to translate it. All five messages below are real g++ 14 -Wall -Wextra output with file names, line numbers, and column markers stripped; the wording may vary slightly by compiler version.

11a — Remove the braces. Write if (age >= 18) with no braces, then two cout lines under it, both indented. Set age to 8.

warning: this 'if' clause does not guard... [-Wmisleading-indentation]
    if (age >= 18)
note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
        cout << "You can vote." << endl;

It compiles anyway, and running it prints:

You can vote.

An 8-year-old can vote. The if controlled exactly one statement (§2.4).

11b — Add a stray semicolon. if (age >= 18); followed by a braced block. Still age = 8.

warning: suggest braces around empty body in an 'if' statement [-Wempty-body]
    if (age >= 18);
warning: this 'if' clause does not guard... [-Wmisleading-indentation]
    if (age >= 18);
note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    {

It runs, and prints:

Adult.

That semicolon was the entire body. The block below it is an unconditional block.

11c — switch on a string. Declare string answer = "yes"; and switch (answer) with case "yes":.

error: switch quantity not an integer
    switch (answer) {

11d — Duplicate a case. Put case 'A': twice in the same switch.

error: duplicate case value
        case 'A':
note: previously used here
        case 'A':

11e — Orphan the else. Put a plain cout statement between the closing brace of an if block and its else.

error: 'else' without a previous 'if'
    else {

Five bugs you would otherwise have met in the dark at 11 p.m. Add each message and its one-line fix to the my_bugs.txt file §2.18 told you to start.


Reps 12–15: Doing It Again

Rep 12 — Count to 20, Three Ways

One program, three for loops (§2.13). First loop prints 1 through 20 on one line, space-separated. Second counts back down from 20 to 1. Third prints only the even numbers — using an if inside the loop, not by changing the step.

Expected output:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 
2 4 6 8 10 12 14 16 18 20 

Yes, every line ends with a space. That is the << " " after the last number, and it is normal.

The third loop is the point of the rep: an if inside a for is the first place both halves of this week touch. Count the numbers on line three — ten of them, not eleven. If you got eleven, you wrote i <= 20 starting from 0 (§2.15).


Rep 13 — Sum 1 to n, Two Ways

Ask for a positive integer n. Guard the read with if (!(cin >> n)). Compute 1 + 2 + ... + n with an accumulator in a for loop, then compute the same sum with the closed-form formula n * (n + 1) / 2, then print both and print whether they match with boolalpha (§2.13). Use long long for the sums and static_cast<long long>(n) in the formula, exactly as code/for_loop.cpp does.

Run it three times: 10, 100, 1000.

Expected output — three runs, in that order:

Enter a positive integer n: Sum via loop:    55
Sum via formula: 55
Match: true
Enter a positive integer n: Sum via loop:    5050
Sum via formula: 5050
Match: true
Enter a positive integer n: Sum via loop:    500500
Sum via formula: 500500
Match: true

Match: true is the line that matters, not the numbers. Two independent routes to the same answer is your substitute for a grader looking over your shoulder. Build the habit here; you will use it for the rest of the course.


Rep 14 — Sentinel Sum

Ask the user for integers, one per line, until they type -1. Accumulate the total, count the entries (not counting the -1), and afterward print the total, the count, and the average. Two guards are required: the read must be guarded with if (!(cin >> input)) { ... break; } so a broken cin cannot hang you (§2.12 sidebar), and the average must be guarded with if (count > 0) and use static_cast<double> so it neither divides by zero nor loses the fraction (§2.13).

Run A — feed 5, 3, 8, -1:

Enter integers, one per line. Type -1 to stop.
Total: 16 across 3 value(s).
Average: 5.33333

Run B — feed -1 immediately:

Enter integers, one per line. Type -1 to stop.
Total: 0 across 0 value(s).
Average: no values entered.

Run C — feed nothing at all (empty Stdin box in OnlineGDB):

Enter integers, one per line. Type -1 to stop.
(input ended)
Total: 0 across 0 value(s).
Average: no values entered.

Run C is the one that separates a working program from a hanging one. Without the guarded read, that run loops forever printing nothing, and you have no error message to search for. Test it every time you write a sentinel loop.


Rep 15 — Until You Comply

Ask for a number from 1 to 10 with a do…while loop that re-prompts until the user complies (§2.11). Count attempts. Reject out-of-range values with a message that names the bad value. Guard the read here too. Remember the semicolon after } while (...).

Run A — feed 42, 0, 7:

Pick a number from 1 to 10:   42 is out of range. Try again.
Pick a number from 1 to 10:   0 is out of range. Try again.
Pick a number from 1 to 10: You picked 7 after 3 attempt(s).

Run B — feed 7 on the first try:

Pick a number from 1 to 10: You picked 7 after 1 attempt(s).

Run B is why do…while fits: the first prompt behaves exactly like every re-prompt, so no fake starting value is needed. This fifteen-line skeleton — loop, condition, counter, validation — is the exact shape Project 2 needs.


Reps 16–18: Shape, Depth, and Escape

Rep 16 — Skip and Stop

Read integers with while (cin >> input). Negative values are skipped with continue (count them separately). A 0 ends the run with break. Everything else is added to a total and counted (§2.12). Afterward print how many you kept, how many you skipped, and the total.

Feed it 5 -3 10 -8 7 0 on one line.

Expected output:

Type integers. Negatives are skipped; 0 ends the run.
Kept 3 value(s), skipped 2 negative(s).
Total of positives: 22

Check the arithmetic yourself: 5 + 10 + 7 is 22, two negatives never reached the accumulator, and the 0 stopped everything before it was counted. If your total is 22 but your kept count is 4, you incremented the counter before the break.


Rep 17 — Rows, Columns, and a Triangle

Read rows and cols. Then two nested loops (§2.14).

The first prints a labeled rectangle — Row 1: followed by cols stars, and so on — with a fixed inner bound. The second prints a triangle, where the inner bound depends on the outer variable (col <= row). Both keep a counter of how many times the inner body ran, and print it.

Before you run it, with rows = 4 and cols = 6: write down on paper how many times each inner body runs. Then feed it 4 and 6.

Expected output:

Rows: Columns: Row 1: * * * * * * 
Row 2: * * * * * * 
Row 3: * * * * * * 
Row 4: * * * * * * 
Rectangle inner body ran 24 times.

* 
* * 
* * * 
* * * * 
Triangle inner body ran 10 times.

24 is 4 × 6 — iteration counts multiply. 10 is 1 + 2 + 3 + 4 — the dependent inner bound is what builds anything shaped like a pyramid or a table. If your paper said 24 and 10, your model of nested loops is correct.


Rep 18 — Five Broken Loops

Same drill as Rep 11, on the other half of the week. Break, compile, read, fix. Real g++ 14 output, prefixes stripped, wording may vary slightly by compiler version.

18a — Forget the increment. Write int i = 1; while (i <= 10) { cout << i << " "; } with no i++. It compiles clean. It runs forever. Here are the first 40 values it printed before it was killed:

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 

Stop it now. In OnlineGDB the Run control becomes a Stop control — click it, or reload the tab. In a local terminal press Ctrl+C. Nothing is damaged (§2.16). You have now lived through an infinite loop on purpose, which is much cheaper than meeting your first one at midnight. Add the i++ and confirm it prints 1 through 10.

18b — Stray semicolon after for. Write for (int i = 1; i <= 5; i++); with the cout indented underneath.

warning: this 'for' clause does not guard... [-Wmisleading-indentation]
    for (int i = 1; i <= 5; i++);
note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'for'
        cout << "star" << endl;

It compiles and runs, and prints star exactly once. The semicolon was the whole body.

18c — Declare the accumulator inside the loop. Move int sum = 0; inside the loop body, then print sum after the loop.

error: 'sum' was not declared in this scope
    cout << "Sum: " << sum << endl;

Scope. The variable was created fresh every pass and destroyed at the closing brace, so everything you accumulated was thrown away — and the compiler caught it only when you tried to read it afterward (§2.13).

18d — Drop the semicolon after do…while. Write } while (n < 0) with no ;.

error: expected ';' before 'cout'
    } while (n < 0)
                   ;

    cout << "Got it: " << n << endl;

Note where the error points: at the cout, which is fine. When an error says “expected ;” and the named line looks correct, check the line above (§2.18).

18e — Use the loop counter after the loop. Print i after a for (int i = 0; i < 5; i++) loop ends.

error: 'i' was not declared in this scope
    cout << "last i was " << i << endl;

A variable declared in a for header lives only inside that loop. Declare it before the loop if you need it after.

Five more entries for my_bugs.txt. You have now met, on purpose and in daylight, ten of the errors that would otherwise have found you in the dark.


Done? One Last Thing.

Open a fresh, blank file — from_memory_2.cpp. Close this page. Close the chapter. No AI, no autocomplete, no looking back. Both halves of the week, from memory:

  1. Ask for a positive integer n.
  2. A for loop from 1 to n with an if inside it that prints only the multiples of 3, space-separated on one line, and increments a counter each time it finds one.
  3. After the loop, an if/else if/else cascade on that counter: None. when it is 0, A few. when it is under 5, Plenty. otherwise — each on a line that also reports the count and n.

Run it three times, feeding 20, 10, 2.

Expected output — three runs, in that order:

Enter a positive integer n: 3 6 9 12 15 18 
Found 6 multiples of 3 up to 20. Plenty.
Enter a positive integer n: 3 6 9 
Found 3 multiples of 3 up to 10. A few.
Enter a positive integer n: 
Found 0 multiples of 3 up to 2. None.

The third run is the one to check hardest: the loop body never printed anything, so the line is empty — but the endl after the loop still ran, and the cascade still reported honestly. A loop that does nothing is not the same as a loop that is broken.

If it worked the first time, you have the move. If it did not, fix it, then delete the file and write it again from scratch in a new one. Repeat until it comes out cold. That is what “from memory” means, and it is the difference between a five-hour project and a twelve-hour one.

Then take the §2.20 Checkpoint honestly. Pass bar is 6 of 7. If you score 5 or below, re-drill instead of starting the project — that is the cheapest trade available to you this week.


Up next: Project 2 — Project 2: The Coffee Shop Conversation. Sketch your endings in plain English on paper before you write a single cout.