Debugging Exercises — Decisions
How to work: read the code, predict the symptom by hand (a dry run on the given test inputs), then check the hint ladder only as needed — H1 nudges, H2 locates, H3 explains the fix. Each program compiles cleanly unless stated: the bug is in the logic, which no compiler can catch. Fix, re-run the tests, and confirm the corrected output.
D1 — The missing =
// Rule: children under 12 eat free.
int age;
std::cin >> age;
if (age = 12) // compiles with a warning under -Wall
{
std::cout << "Free meal\n";
}
else
{
std::cout << "Pay 500\n";
}
Task: the rule says under-12s eat free, but the program prints Free meal for age 20 and for age 5 alike. Fix it.
Hints
- H1: what is the value of the condition
age = 12? - H2: the condition assigns 12 to
ageand evaluates to 12 — non-zero, always true. - H3:
if (age < 12)— comparison, not assignment. The bug family lives in Lesson 2 §1; compile with-Walland gcc flags this as a warning.
D2 — The unbraced body
// Rule: passing students get PASS and a congratulations line.
int marks;
std::cin >> marks;
if (marks >= 40)
std::cout << "PASS\n";
std::cout << "Congratulations!\n";
Task: a failing student (marks 25) still sees Congratulations!. Why, and fix it.
Hints
- H1: which statements belong to the
if? Count them with the brace rule from Lesson 1 §7. - H2: the
ifowns exactly one statement; the congratulations is unconditional. - H3: brace the two-line body. This is why the course rule is always brace.
D3 — The stray semicolon
// Rule: refuse out-of-range marks.
int marks;
std::cin >> marks;
if (marks < 0 || marks > 100);
{
std::cout << "Invalid marks\n";
return 1;
}
Task: the program refuses every mark, including valid ones. Find it.
Hints
- H1: what statement sits between the
if (…)and the block? - H2: the semicolon is an empty statement — the whole decision is made and discarded; the block runs always.
- H3: delete the semicolon. Related trap family: Lesson 1 §8 M6.
D4 — The unordered ladder
// Grading: A >= 80, B >= 70, C >= 60, D >= 40, else F.
int marks;
std::cin >> marks;
if (marks >= 40)
{
std::cout << "D\n";
}
else if (marks >= 60)
{
std::cout << "C\n";
}
else if (marks >= 70)
{
std::cout << "B\n";
}
else if (marks >= 80)
{
std::cout << "A\n";
}
else
{
std::cout << "F\n";
}
Task: every mark from 40 upward prints D; 85 prints D. Reorder so the intended grading works, and state the ladder property that made the original wrong (Lesson 1 §5).
Hints
- H1: when is the second question even asked?
- H2: each
elsemeans “and not any condition above” — 85 passes>= 40first and never reaches>= 80. - H3: most-demanding-first: 80, 70, 60, 40, else F.
D5 — The impossible condition
// Rule: warn when temperature is out of the safe band 10..30.
double temp;
std::cin >> temp;
if (temp >= 10 && temp <= 30)
{
std::cout << "Warning: outside safe band\n";
}
else
{
std::cout << "OK\n";
}
Task: the warning never appears — even for 45°C. One character is the culprit class: which operator is wrong?
Hints
- H1: trace the condition for
temp = 45: what is45 >= 10?45 <= 30? - H2: “outside the band” is an OR of two violations, not an AND of two memberships (Lesson 2 §6, inverted range).
- H3:
if (temp < 10 || temp > 30)— and the De Morgan flip in Lesson 2 §4 confirms it’s the exact opposite of the in-range test.
D6 — The flipped boundary
// Rule: scholarship for marks of 60 or more.
int marks;
std::cin >> marks;
if (marks > 60)
{
std::cout << "Scholarship\n";
}
else
{
std::cout << "No scholarship\n";
}
Task: the rule says “60 or more”, but marks of exactly 60 get No scholarship. Which test value catches this, and what is the one-character fix? Then state the general flip rule (Lesson 2 §5).
Hints
- H1: put 60 into the condition. True or false?
- H2:
>excludes the edge; “or more” includes it. - H3:
marks >= 60. The opposite of>= 60is< 60— never<= 59mental gymnastics, never keeping the same edge with a flipped family.
D7 — The missing default
char cmd;
std::cin >> cmd;
switch (cmd)
{
case 'y':
std::cout << "Confirmed\n";
break;
case 'n':
std::cout << "Cancelled\n";
break;
}
Task: a user types x and the program says nothing at all — they can’t tell their keypress was received. Add the missing piece and decide what it should print (echo the input!).
Hints
- H1: what handles “no label matched” in a switch? (Lesson 3 §1)
- H2:
default:is the switch’s finalelse. - H3:
default: std::cout << "Unknown command: " << cmd << '\n';— feedback turns silent misfires into visible, fixable ones.
D8 — The leaky switch
// Rule: level 1 prints Intro, level 2 prints Intro + Standard, level 3 prints all three.
switch (level)
{
case 1:
std::cout << "Intro\n";
break;
case 2:
std::cout << "Standard\n";
case 3:
std::cout << "Advanced\n";
break;
}
Task: level 2 was supposed to print exactly Standard\nAdvanced — which it does. But level 3 prints Advanced too, and the client now reports: “level 1 must print Intro only” (it does) — however the real bug the tester found: entering level 5 prints nothing. Two fixes: (1) make level 5 (any other level) print Invalid level; (2) the spec changed — level 2 must now print Standard only. Fix both without breaking 1 or 3.
Hints
- H1: what runs for
level = 5today? What should? - H2: (1) is the
defaultfrom D7; (2) — look at whatcase 2:leaks into. - H3: add
default:with the message; put abreak;afterStandard\n(the leak was load-bearing only until the spec changed — now it’s just wrong).
D9 — The chained comparison
// Rule: teenager is age 13..19 inclusive.
int age;
std::cin >> age;
if (13 <= age <= 19)
{
std::cout << "Teenager\n";
}
else
{
std::cout << "Not a teenager\n";
}
Task: age 45 prints Teenager. Explain why the compiler accepts this and what it actually computes, then fix it. (Full walk-through: P7.)
Hints
- H1: evaluate
(13 <= age)for age 45 first — it’s abool. Then evaluate(that) <= 19. - H2:
boolconverts to 0 or 1;1 <= 19is always true (Lesson 2 §2). - H3:
age >= 13 && age <= 19.
D10 — The dangling else
// Rule: adults with ID enter; adults without ID are turned away; minors denied.
int age;
bool hasId;
std::cin >> age >> hasId;
if (age >= 18)
if (hasId)
std::cout << "Enter\n";
else
std::cout << "Denied\n";
Task: a minor (age 15) prints nothing at all. To which if does that else bind, and why? Rewrite with braces so the structure matches the rule. (Binding rule: Lesson 1 §6.)
Hints
- H1: which
ifis unmatched when theelsearrives? Indentation lies; binding is nearest-unmatched. - H2: the
elsebelongs to the innerif (hasId)— so adults-without-ID get “Denied” and minors fall through both branches to nothing. - H3: brace every level:
if (age >= 18) { if (hasId) { std::cout << "Enter\n"; } else { std::cout << "Denied (no ID)\n"; } } else { std::cout << "Denied (minor)\n"; }
Fix-list recap
| Hunt | Bug class | Portable lesson |
|---|---|---|
| D1 | = vs == |
-Wall is your friend; compare, don’t assign |
| D2 | unbraced body | brace every body, even one-liners |
| D3 | stray ; |
empty statement eats the decision |
| D4 | ladder order | most-demanding-first or self-contained ranges |
| D5 | AND vs OR | “outside a band” = OR of violations |
| D6 | boundary flip | the opposite of >= x is < x |
| D7 | missing default | every menu needs an else |
| D8 | leaky case + missing default | wall every case; handle the unmatched |
| D9 | chained comparison | bools are 0/1 — split the range |
| D10 | dangling else | braces make binding visible |
Each class also appears in the mistake galleries — after your hunt, the table entry reads differently: as confirmation, not revelation.