# Exercises

### Exercises

This section collects the exercises for the chapter. They are meant to be small programs. Each one should compile and run.

Exercise 3-1. Write a block expression that sets `x` to `10 + 20`.

```zig
const x = blk: {
    break :blk 10 + 20;
};
```

Exercise 3-2. Write a block expression that classifies an integer as `"small"` or `"large"`.

```zig
const label = classify: {
    if (n < 100) break :classify "small";
    break :classify "large";
};
```

Exercise 3-3. Put a `defer` inside an inner block and observe when it runs.

```zig
const std = @import("std");

pub fn main() void {
    std.debug.print("before\n", .{});

    {
        defer std.debug.print("leaving inner block\n", .{});
        std.debug.print("inside\n", .{});
    }

    std.debug.print("after\n", .{});
}
```

Exercise 3-4. Try to return two different value types from one block expression and read the compiler error.

```zig
const x = blk: {
    if (true) break :blk 10;
    break :blk "ten";
};
```

This should fail. One branch gives an integer. The other gives a string.

Exercise 3-5. Write an `if` expression that returns the smaller of two integers.

```zig
const smaller = if (a < b) a else b;
```

Exercise 3-6. Rewrite an ordinary `if` statement as an expression.

Before:

```zig
var result: i32 = 0;

if (n < 0) {
    result = -n;
} else {
    result = n;
}
```

After:

```zig
const result = if (n < 0) -n else n;
```

Exercise 3-7. Use `if` with an optional value.

```zig
const std = @import("std");

pub fn main() void {
    const maybe_name: ?[]const u8 = "zig";

    if (maybe_name) |name| {
        std.debug.print("{s}\n", .{name});
    } else {
        std.debug.print("no name\n", .{});
    }
}
```

Exercise 3-8. Write a function that returns `"even"` or `"odd"` using an `if` expression.

```zig
fn parity(n: i32) []const u8 {
    return if (@mod(n, 2) == 0) "even" else "odd";
}
```

Exercise 3-9. Write a `switch` that converts digits `0` through `9` to their English names.

```zig
fn digitName(n: u8) []const u8 {
    return switch (n) {
        0 => "zero",
        1 => "one",
        2 => "two",
        3 => "three",
        4 => "four",
        5 => "five",
        6 => "six",
        7 => "seven",
        8 => "eight",
        9 => "nine",
        else => "not a digit",
    };
}
```

Exercise 3-10. Write a `switch` over an enum named `Direction` with cases `north`, `south`, `east`, and `west`.

```zig
const Direction = enum {
    north,
    south,
    east,
    west,
};

fn directionName(d: Direction) []const u8 {
    return switch (d) {
        .north => "north",
        .south => "south",
        .east => "east",
        .west => "west",
    };
}
```

Exercise 3-11. Add a new enum case and observe which switches must change.

```zig
const Direction = enum {
    north,
    south,
    east,
    west,
    center,
};
```

After adding `center`, the previous `switch` no longer covers every case. Add:

```zig
.center => "center",
```

Exercise 3-12. Write a tagged union for a simple token: integer, left parenthesis, right parenthesis, plus, and minus. Use `switch` to print each token.

```zig
const std = @import("std");

const Token = union(enum) {
    integer: i64,
    left_paren,
    right_paren,
    plus,
    minus,
};

fn printToken(tok: Token) void {
    switch (tok) {
        .integer => |n| std.debug.print("integer {d}\n", .{n}),
        .left_paren => std.debug.print("(\n", .{}),
        .right_paren => std.debug.print(")\n", .{}),
        .plus => std.debug.print("+\n", .{}),
        .minus => std.debug.print("-\n", .{}),
    }
}
```

Exercise 3-13. Write a `while` loop that prints the numbers from `1` to `10`.

```zig
var i: usize = 1;

while (i <= 10) : (i += 1) {
    std.debug.print("{d}\n", .{i});
}
```

Exercise 3-14. Write a loop that prints only even numbers below `20`.

```zig
var i: usize = 0;

while (i < 20) : (i += 1) {
    if (i % 2 != 0) continue;
    std.debug.print("{d}\n", .{i});
}
```

Exercise 3-15. Write a search loop that finds the first zero in an array.

```zig
const data = [_]i32{ 3, 4, 0, 8 };

var i: usize = 0;
const index = while (i < data.len) : (i += 1) {
    if (data[i] == 0) break i;
} else data.len;
```

Exercise 3-16. Change the search loop so it returns `null` when no zero is present.

```zig
const data = [_]i32{ 3, 4, 9, 8 };

var i: usize = 0;
const index: ?usize = while (i < data.len) : (i += 1) {
    if (data[i] == 0) break i;
} else null;
```

Exercise 3-17. Write a `for` loop that prints every element in an array.

```zig
const data = [_]i32{ 10, 20, 30 };

for (data) |x| {
    std.debug.print("{d}\n", .{x});
}
```

Exercise 3-18. Print each element with its index.

```zig
const data = [_]i32{ 10, 20, 30 };

for (data, 0..) |x, i| {
    std.debug.print("{d}: {d}\n", .{ i, x });
}
```

Exercise 3-19. Use pointer capture to double every number in an array.

```zig
var data = [_]i32{ 1, 2, 3, 4 };

for (&data) |*x| {
    x.* *= 2;
}
```

Exercise 3-20. Write a `for` expression that returns the index of the first even number, or `null` if there is none.

```zig
const data = [_]i32{ 1, 3, 7, 10 };

const index: ?usize = for (data, 0..) |x, i| {
    if (@mod(x, 2) == 0) break i;
} else null;
```

Exercise 3-21. Write a loop that stops when it finds zero.

```zig
const data = [_]i32{ 5, 4, 0, 2 };

for (data) |x| {
    if (x == 0) break;
    std.debug.print("{d}\n", .{x});
}
```

Exercise 3-22. Write a loop that skips negative numbers and prints the rest.

```zig
const data = [_]i32{ 3, -1, 5, -8, 13 };

for (data) |x| {
    if (x < 0) continue;
    std.debug.print("{d}\n", .{x});
}
```

Exercise 3-23. Write nested loops that search a two-dimensional array.

```zig
const table = [_][3]i32{
    .{ 1, 2, 3 },
    .{ 4, 5, 6 },
    .{ 7, 8, 9 },
};

const target = 8;

for (table, 0..) |row, r| {
    for (row, 0..) |value, c| {
        if (value == target) {
            std.debug.print("found at {d}, {d}\n", .{ r, c });
        }
    }
}
```

Exercise 3-24. Rewrite the nested search using a labeled `break`.

```zig
const table = [_][3]i32{
    .{ 1, 2, 3 },
    .{ 4, 5, 6 },
    .{ 7, 8, 9 },
};

const target = 8;

const found = search: for (table, 0..) |row, r| {
    for (row, 0..) |value, c| {
        if (value == target) {
            break :search .{ r, c };
        }
    }
} else null;
```

Exercise 3-25. Write a program with two deferred prints and observe the order.

```zig
const std = @import("std");

pub fn main() void {
    defer std.debug.print("one\n", .{});
    defer std.debug.print("two\n", .{});
}
```

The output is:

```text
two
one
```

Exercise 3-26. Put a `defer` inside an inner block and observe when it runs.

```zig
const std = @import("std");

pub fn main() void {
    {
        defer std.debug.print("inner defer\n", .{});
        std.debug.print("inner body\n", .{});
    }

    std.debug.print("outer body\n", .{});
}
```

Exercise 3-27. Put a `defer` inside a loop and observe that it runs once per iteration.

```zig
const std = @import("std");

pub fn main() void {
    for (0..3) |i| {
        defer std.debug.print("leave {d}\n", .{i});
        std.debug.print("enter {d}\n", .{i});
    }
}
```

Exercise 3-28. Open a file and use `defer` to close it.

```zig
const std = @import("std");

pub fn main() !void {
    const file = try std.fs.cwd().openFile("input.txt", .{});
    defer file.close();

    _ = file;
}
```

