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.zigExercise 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.zigI.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.