Programming Fundamentals Using C++

Case Studies · Tier 4 · Advanced

Lectures L23–L30 · Modules 12–15 · think ~5 minutes · paper only. Cases ascend in difficulty within the tier. Worked solutions: instructor area only.


PF-CS-061 · The Off-by-One Autopsy

<details><summary>Hints (progressive)</summary>

  1. Valid indices are 0…n−1; the initial high violates that.
  2. Trace: low=0, high=4 → mid=2 compares a[2]=6 < 8 → low=3, high=4 → mid=3... watch the boundary.
  3. Fix: high = n−1 with low <= high, or high = n with low < high — pick one discipline.

</details>


PF-CS-062 · Pointer Cipher Walk

<details><summary>Hints (progressive)</summary>

  1. p++ advances by sizeof(char) — one byte — to the next cell.
  2. The terminator is the only sentinel: dereference-compare, don't compare pointers.
  3. The one-past-the-end pointer may exist but must never be dereferenced.

</details>


PF-CS-063 · The Alias Explosion

<details><summary>Hints (progressive)</summary>

  1. x is the object; r is an alias; p holds an address.
  2. r = 5, *p = 9, x = 11: all three names report the survivor.
  3. r cannot be re-seated to alias y; p can be repointed.

</details>


PF-CS-064 · Out-Parameter vs Return

<details><summary>Hints (progressive)</summary>

  1. A bool return demands an if at the call site — visible control flow.
  2. Sentinel values collide with legal data.
  3. The out-parameter plus bool return separates "did it work" from "what it was".

</details>


PF-CS-065 · The Dangling Return

<details><summary>Hints (progressive)</summary>

  1. Automatic locals die at the closing brace.
  2. The returned address is dangling: dereferencing is UB — anything may happen.
  3. Return the int by value (copy is cheap); pointers out only for storage the caller owns.

</details>


PF-CS-066 · Leak Hunter

<details><summary>Hints (progressive)</summary>

  1. Early returns and exceptions skip the delete.
  2. One owner per allocation; every path frees — or no manual new at all.
  3. A local std::vector<int> frees itself: RAII beats discipline.

</details>


PF-CS-067 · Grow-on-Demand Array

<details><summary>Hints (progressive)</summary>

  1. Full → allocate 2×, copy, free the old block.
  2. Capacities: 1, 2, 4, 8, 16, 32 — 17 pushes land in 32.
  3. Total copies ≈ 2n: doubling makes the average push O(1); +10 growth makes it O(n) per push on average... wait, decide: which is it and why?

</details>


PF-CS-068 · Struct Record Migration

<details><summary>Hints (progressive)</summary>

  1. struct Student { name, id, gpa }; array of Student.
  2. Swap copies whole records: t = a[i]; a[i] = a[j]; a[j] = t.
  3. Half-migrated data keeps the misalignment bug alive — migrate the whole record.

</details>


<details><summary>Hints (progressive)</summary>

  1. findItem returns an index or −1; the caller interprets.
  2. The transaction loop owns validation policy; findItem only finds.
  3. Final table prints after the sentinel: one loop, three verdict branches.

</details>


PF-CS-070 · Top-K Report

<details><summary>Hints (progressive)</summary>

  1. One pass to find the max is O(n); extract k times is O(kn).
  2. Mark extracted records as used (or swap them to the back).
  3. k ≈ n → just sort: O(n log n) beats O(n²).

</details>


PF-CS-071 · Binary Search Contract Test

<details><summary>Hints (progressive)</summary>

  1. Empty must return "not found" without indexing — test it first.
  2. Two elements exercise mid == low and mid == high both.
  3. Absent-below with low <= high and a wrong mid-step can loop forever — that's the discriminator.

</details>


PF-CS-072 · Median Without Full Sort

<details><summary>Hints (progressive)</summary>

  1. The caller's array must survive — copy, sort the copy.
  2. Even n averages the two middle elements — careful with integer division.
  3. n == 0 is a contract violation: reject before touching anything.

</details>


PF-CS-073 · The NullPointerException Class

<details><summary>Hints (progressive)</summary>

  1. Rule: no dereference without proof of validity.
  2. Uninitialized pointers: initialize to nullptr at birth.
  3. Use-after-delete: set p = nullptr immediately after delete.

</details>


PF-CS-074 · Struct vs Parallel Arrays Benchmark

<details><summary>Hints (progressive)</summary>

  1. Sorting a field still needs record integrity — parallel arrays fight you.
  2. Adding a field: struct = one line; parallel = every array plus every swap.
  3. Passing a struct copies the unit; passing "a student" from parallel arrays is 3 arguments.

</details>


PF-CS-075 · Two-Key Sort (Name then Score)

<details><summary>Hints (progressive)</summary>

  1. less(a,b) = (a.name < b.name) || (a.name == b.name && a.score < b.score).
  2. Trace two equal names: the score decides; equal both → not less either way.
  3. A contradictory comparator (a<b and b<a) corrupts any sort — transitivity is the guard.

</details>


PF-CS-076 · The Cost Ladder

<details><summary>Hints (progressive)</summary>

  1. One query → linear; many queries on small ranges → counting.
  2. Sort once pays off only when q log n beats q·n... compare directly.
  3. The counting array's memory is O(range) — the range bound is the catch.

</details>


PF-CS-077 · Merge Sorted Queues

<details><summary>Hints (progressive)</summary>

  1. Take the smaller head; advance that index only.
  2. When one side empties, copy the other's tail directly.
  3. Each comparison emits one element; ≤ m+n−1 emissions come from comparisons.

</details>


PF-CS-078 · The Nightly Settlement File

<details><summary>Hints (progressive)</summary>

  1. getline + istringstream per line: malformed lines are data, not crashes.
  2. Withdraw > balance → skip with reason; both counters advance... decide which counters.
  3. Empty file: report prints zeros — and that is correct behavior, not an error.

</details>


PF-CS-079 · Configuration with Defaults

<details><summary>Hints (progressive)</summary>

  1. Store seen-keys; a missing key falls back at print time.
  2. Unknown keys: warn and continue (policy — justify it).
  3. A later line could override an earlier one — last-write-wins, then report.

</details>


PF-CS-080 · The Self-Validating Form

<details><summary>Hints (progressive)</summary>

  1. Two exits: valid input, or stream closure (EOF) — handle both.
  2. Per-field rejection counters make the summary useful to UI designers.
  3. Never trust the stream state between reads: clear-and-check is the pattern.

</details>

Programming Fundamentals Using C++ · C++17 · 16 weeksBack to top ↑