# 3.x Chapter 3 summary and quiz
> Debugging terms in review, plus a quiz of real broken programs to hunt through.
Source: https://learnrust.net/chapter-3/chapter-3-summary-and-quiz/
Chapter 3 in one breath, then the quiz, which for this chapter means: here are some broken programs, go be the process.
## Quick review
A **syntax error** breaks the grammar and dies at compile time. A **semantic error** (**logic error**) compiles and does the wrong thing. Rust reclassifies much of the traditional semantic-error category into compile-time errors, and catches another slice at runtime as a **panic**: an immediate, honest stop with a file-and-line report (dividing by a zero variable, a failing `expect`). What remains is the silent wrong answer, which is yours.
Debugging follows six steps: reproduce, locate, understand, plan, fix, retest (including the neighbors). Reproduce *before* theorizing; fix only what you understand; a vanished symptom is evidence, not proof.
Locating is search-space management. Inspect what's small and recent (the bug is usually in the last thing you touched); when staring fails, switch to running experiments: check values at the *seams* between functions, halve the territory with each observation, comment chunks out to test involvement, and change one thing per experiment, undoing as you go.
Programs have two output streams: stdout (`println!`, the product) and stderr (`eprintln!`, the commentary), and redirection (`>`) separates them. The **dbg!** macro is purpose-built instrumentation: it prints `[file:line:column] expression = value` to stderr and *returns the value*, so it wraps any expression in place. Probes are temporary; sweep them before calling work done.
A **debugger** pauses a live program: **breakpoints** choose where, **stepping** (over, into, out) moves in controlled doses, **watching** reads variables, and the **call stack** shows the chain of calls in progress, top to `main`. Use the dev profile, since release builds shed the debug info and rearrange the code.
And the prevention habits, cheaper than any hunt: build in small compiled steps, keep functions small and single-jobbed, never mix cleanup with behavior changes, ask what the worst caller could do, heed warnings and Clippy, and (chapter 14 trailer) write what "correct" means as runnable `#[test]` functions.
## Quiz time
**Question #1**
A user reports this program always answers `0` plus the second number, whatever they type first. Find the bug, name which step-2 evidence would have exposed it fastest, and fix it.
```rust
fn main() {
let x = 0;
read_number();
let y = read_number();
println!("{} + {} is {}", x, y, x + y);
}
fn read_number() -> i32 {
println!("Enter a whole number:");
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("failed to read input");
input.trim().parse().expect("that wasn't a whole number")
}
```
Show solution
The first `read_number()` call's return value is *discarded*: the statement runs the prompt-and-read, then throws the result away, and `x` stays the 0 it was initialized to. The fix:
```rust
let x = read_number();
let y = read_number();
```
Fastest evidence: `dbg!(x)` (or a breakpoint) just before the `println!`, showing `x = 0` no matter what was typed; the seam check immediately clears `read_number`'s internals and points at the wiring in `main`. (The program even prompts twice and uses only one answer, a symptom visible with no tools at all: it *asks*, then ignores you, like a waiter.)
**Question #2**
This one compiles with a warning and then dies at runtime. Explain the crash, find the bug, and say what the warning was trying to tell you.
```rust
fn main() {
let mut x = read_number();
let y = 0;
x = read_number();
println!("{} / {} is {}", x, y, x / y);
}
fn read_number() -> i32 {
println!("Enter a whole number:");
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("failed to read input");
input.trim().parse().expect("that wasn't a whole number")
}
```
```
Enter a whole number:
8
Enter a whole number:
2
thread 'main' (1127017) panicked at src/main.rs:5:37:
attempt to divide by zero
```
Show solution
The second input was *meant* to become `y`, but the line assigns it to `x` again (a copy-paste classic). `y` keeps its placeholder 0, and the division panics. The fix is the intended wiring, which also dissolves the `mut` and the placeholder:
```rust
let x = read_number();
let y = read_number();
```
The warning ("value assigned to `x` is never read", on the *first* read) was the whole story in advance: a value was computed, stored, and overwritten before any use, which is precisely the bug. Warnings first, then tools.
**Question #3**
No code to run for this one; predict from your mental model. The program below is paused by a breakpoint on the marked line. What does the call stack panel show, top to bottom?
```rust
fn main() {
outer();
}
fn outer() {
helper();
}
fn helper() {
let x = 1; // breakpoint here
println!("{x}");
}
```
Show solution
Top to bottom: `helper`, `outer`, `main`. The top entry is where execution is paused; each entry below is a function mid-call, waiting for the one above it to return; `main` anchors the bottom of every Rust stack.
That's the on-ramp milestone complete: tools installed, language basics, functions, and now debugging. Chapter 4 starts the language's real depth: what those `i32`s have been all along, the rest of their family, and the first appearance of `if`. The programs get noticeably more interesting from here.