Skip to content

Exercises

1. Write a function increment that takes i32 and adds 1 to the pointed-to value.

  1. Write a function increment that takes *i32 and adds 1 to the pointed-to value.
fn increment(n: *i32) void {
    // ...
}
  1. Write a function swap that exchanges two integers through pointers.
fn swap(a: *i32, b: *i32) void {
    // ...
}
  1. Declare a constant integer, take its address, and observe the type of the pointer.
const x: i32 = 10;
const p = &x;
  1. Try to modify a value through a *const i32 pointer. Read the compiler error.

  2. Write a function doubleAll that doubles every element in a mutable slice.

fn doubleAll(items: []i32) void {
    // ...
}
  1. Write a function countZeroes that counts how many elements in []const i32 are zero.

  2. Create an array of five integers. Take a slice of the middle three elements and print them.

  3. Rewrite the previous exercise using a many-item pointer and a separate length.

  4. Write a function that returns the largest value in a slice.

fn max(items: []const i32) i32 {
    // ...
}
  1. Write a function that fills a slice with a chosen byte.
fn fill(items: []u8, value: u8) void {
    // ...
}
  1. Create a sentinel-terminated string pointer.
const name: [*:0]const u8 = "zig";

Write a function that counts bytes until the zero sentinel is reached.

  1. Print the alignment of these types:
u8
u16
u32
u64
f32
f64

Use @alignOf.

  1. Create a byte array and interpret four bytes as a little-endian integer using std.mem.readInt.

  2. Declare a weakly aligned pointer.

*align(1) i32

Try assigning it directly to *i32. Read the compiler error. Then use @alignCast.

  1. Write a function that takes a slice and reverses its elements in place.
fn reverse(items: []i32) void {
    // ...
}
  1. Allocate an array dynamically with an allocator, assign values, print them, and free the memory.

  2. Write a function that allocates and returns a slice of ten integers.

fn makeNumbers(
    allocator: std.mem.Allocator,
) ![]i32 {
    // ...
}

Free the slice in the caller.

  1. Write a function that incorrectly returns a pointer to a local variable.
fn bad() *i32 {
    // ...
}

Explain why the returned pointer is invalid.

  1. Define a struct containing a slice.
const Buffer = struct {
    data: []u8,
};

Write a method that sets every byte in the slice to zero.

  1. Write a small string-copy function using slices.
fn copy(dst: []u8, src: []const u8) usize {
    // ...
}

Return the number of bytes copied.

  1. Write a function using pointer arithmetic over a many-item pointer.
fn sumMany(ptr: [*]const i32, len: usize) i32 {
    // ...
}

Then rewrite it using a slice.

  1. Explain the difference between these types:
*i32
*const i32
[*]i32
[]i32
[]const i32
?*i32
  1. Explain the difference between ownership and access. Which values in this chapter own storage, and which merely refer to it?

  2. Rewrite a pointer-based function to use ordinary value parameters instead. Compare the two versions.

  3. Write a short note explaining when slices should be preferred over many-item pointers.