Skip to content

Appendix I. Exercise Answers

These are short answers or sketches for selected exercises from the book. Many exercises have several reasonable solutions. The important part is clarity and correctness.

These are short answers or sketches for selected exercises from the book. Many exercises have several reasonable solutions. The important part is clarity and correctness.

I.1 Hello, Zig

Exercise 1-1. Run the first program.

zig run main.zig

Exercise 1-2. Change the message.

const std = @import("std");

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

Exercise 1-3. Print two lines.

const std = @import("std");

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

Exercise 1-4. Print a string value.

const std = @import("std");

pub fn main() void {
    const name = "zig";

    std.debug.print("{s}\n", .{name});
}

I.2 Variables and Types

Exercise 2-1. Swap two integers.

var a: i32 = 10;
var b: i32 = 20;

const tmp = a;
a = b;
b = tmp;

Exercise 2-2. Print an integer and a float.

const std = @import("std");

pub fn main() void {
    const i: i32 = 10;
    const f: f64 = 3.14;

    std.debug.print("{d} {d}\n", .{ i, f });
}

Exercise 2-3. Convert an integer.

const x: i32 = 10;
const y: u32 = @intCast(x);

I.3 Control Flow

Exercise 3-1. Print numbers from 0 to 9.

const std = @import("std");

pub fn main() void {
    var i: usize = 0;

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

Exercise 3-2. Sum an array.

const items = [_]i32{ 1, 2, 3, 4 };

var sum: i32 = 0;

for (items) |item| {
    sum += item;
}

Exercise 3-3. Use switch.

switch (ch) {
    'a', 'e', 'i', 'o', 'u' => vowel(),
    else => consonant(),
}

I.4 Functions

Exercise 4-1. Maximum of two integers.

fn max(a: i32, b: i32) i32 {
    return if (a > b) a else b;
}

Exercise 4-2. Absolute value.

fn abs(x: i32) i32 {
    return if (x < 0) -x else x;
}

Exercise 4-3. Recursive factorial.

fn fact(n: u32) u32 {
    if (n == 0) {
        return 1;
    }

    return n * fact(n - 1);
}

I.5 Arrays and Slices

Exercise 5-1. Reverse an array in place.

fn reverse(items: []u8) void {
    var i: usize = 0;
    var j: usize = items.len;

    while (i < j) {
        j -= 1;

        const tmp = items[i];
        items[i] = items[j];
        items[j] = tmp;

        i += 1;
    }
}

Exercise 5-2. Find the largest value.

fn max(items: []const i32) i32 {
    var m = items[0];

    for (items[1..]) |item| {
        if (item > m) {
            m = item;
        }
    }

    return m;
}

I.6 Structs

Exercise 6-1. Define a point.

const Point = struct {
    x: i32,
    y: i32,
};

Exercise 6-2. Add two points.

fn add(a: Point, b: Point) Point {
    return .{
        .x = a.x + b.x,
        .y = a.y + b.y,
    };
}

Exercise 6-3. Zero constructor.

const Point = struct {
    x: i32,
    y: i32,

    fn zero() Point {
        return .{
            .x = 0,
            .y = 0,
        };
    }
};

I.7 Errors

Exercise 7-1. Return an error for division by zero.

const MathError = error{
    DivideByZero,
};

fn divide(a: i32, b: i32) MathError!i32 {
    if (b == 0) {
        return error.DivideByZero;
    }

    return @divTrunc(a, b);
}

Exercise 7-2. Use try.

const result = try divide(a, b);

Exercise 7-3. Use catch.

const result = divide(a, b) catch 0;

I.8 Optionals

Exercise 8-1. Return the first element or null.

fn first(items: []const i32) ?i32 {
    if (items.len == 0) {
        return null;
    }

    return items[0];
}

Exercise 8-2. Use orelse.

const value = first(items) orelse -1;

I.9 Allocation

Exercise 9-1. Allocate an array.

const buf = try allocator.alloc(u8, 1024);
defer allocator.free(buf);

Exercise 9-2. Duplicate a string.

const copy = try allocator.dupe(u8, text);
defer allocator.free(copy);

I.10 Array Lists

Exercise 10-1. Append numbers.

var list = std.ArrayList(i32).init(allocator);
defer list.deinit();

try list.append(1);
try list.append(2);
try list.append(3);

Exercise 10-2. Sum the list.

var sum: i32 = 0;

for (list.items) |item| {
    sum += item;
}

I.11 Strings

Exercise 11-1. Count spaces.

fn countSpaces(text: []const u8) usize {
    var n: usize = 0;

    for (text) |ch| {
        if (ch == ' ') {
            n += 1;
        }
    }

    return n;
}

Exercise 11-2. Compare two strings.

const same = std.mem.eql(u8, a, b);

I.12 Files

Exercise 12-1. Read a file.

const std = @import("std");

pub fn main() !void {
    const allocator = std.heap.page_allocator;

    const file = try std.fs.cwd().openFile(
        "data.txt",
        .{},
    );
    defer file.close();

    const data = try file.readToEndAlloc(
        allocator,
        1024 * 1024,
    );
    defer allocator.free(data);

    std.debug.print("{s}\n", .{data});
}

Exercise 12-2. Copy standard input to standard output.

const std = @import("std");

pub fn main() !void {
    var buf: [1024]u8 = undefined;

    const stdin = std.io.getStdIn().reader();
    const stdout = std.io.getStdOut().writer();

    while (true) {
        const n = try stdin.read(&buf);

        if (n == 0) {
            break;
        }

        try stdout.writeAll(buf[0..n]);
    }
}

I.13 Generic Functions

Exercise 13-1. Generic swap.

fn swap(comptime T: type, a: *T, b: *T) void {
    const tmp = a.*;
    a.* = b.*;
    b.* = tmp;
}

Exercise 13-2. Generic maximum.

fn max(comptime T: type, a: T, b: T) T {
    return if (a > b) a else b;
}

I.14 Testing

Exercise 14-1. Test a function.

const std = @import("std");

fn add(a: i32, b: i32) i32 {
    return a + b;
}

test "addition" {
    try std.testing.expect(add(2, 3) == 5);
}

Run:

zig test main.zig

I.15 Small Programs

Exercise 15-1. Count lines.

const std = @import("std");

pub fn main() !void {
    var buf: [1024]u8 = undefined;

    const stdin = std.io.getStdIn().reader();

    var count: usize = 0;

    while (true) {
        const n = try stdin.read(&buf);

        if (n == 0) {
            break;
        }

        for (buf[0..n]) |ch| {
            if (ch == '\n') {
                count += 1;
            }
        }
    }

    std.debug.print("{d}\n", .{count});
}

Exercise 15-2. Hex dump.

for (data, 0..) |byte, i| {
    std.debug.print("{x:0>2} ", .{byte});

    if ((i + 1) % 16 == 0) {
        std.debug.print("\n", .{});
    }
}

I.16 Final Note

The exercises are small on purpose. Write short programs first. Keep interfaces narrow. Allocate explicitly. Handle errors immediately. Reduce hidden state. The language becomes simpler as the program becomes clearer.