Zig Arrays and Slices Guide

This guide summarizes key concepts, syntax, and examples related to handling arrays in Zig, including slices, passing arrays between functions, pointers, 2D arrays, and common use cases.


1. Fixed-Size Arrays

const a: [4]i32 = .{1, 2, 3, 4};

2. Slices

const slice: []const i32 = a[0..];

Subslices:

a[1..3]; // elements 1 and 2

3. Passing Arrays and Slices to Functions

Fixed-Size Arrays:

fn printArray(arr: [4]i32) void { ... } // Copies all elements

Slices (Preferred):

fn printSlice(slice: []const i32) void { ... }

4. Pointers to Arrays

const ptr: *[4]i32 = &a;

Used to avoid copying arrays:

fn mutate(ptr: *[4]i32) void {
    ptr.*[0] = 42;
}

5. Raw C-style Pointers

const p: [*]const u8 = "hello";

6. Convert Between Array Types

const a: [4]i32 = .{1, 2, 3, 4};
const slice = a[0..];         // []const i32
const ptr = &a;               // *[4]i32
const raw_ptr = &a[0];        // [*]i32

7. Arena-Allocated Arrays

Fixed-Size 2D Array in Arena:

const matrix = try allocator.create([4][3]f32);
matrix.* = .{ ... }; // set values

Dynamic Outer, Fixed Inner:

var rows = std.ArrayList([3]f32).init(arena);
try rows.append(.{1.0, 2.0, 3.0});

8. Special Syntax

Convert string literals to slices:

const s: []u8 = "hello"[0..];

Create and reference array with inferred length:

const parts = &[_][]const u8{ "hello", " ", "zig" };

9. Common Use Cases

Printing a 2D Matrix

for (matrix.*) |row| {
    for (row) |val| {
        std.debug.print("{} ", .{val});
    }
    std.debug.print("\n", .{});
}

Initializing a String Table

const messages = &[_][]const u8{ "start", "stop", "pause" };

Passing Read-Only Data

fn printAll(msgs: []const []const u8) void {
    for (msgs) |m| std.debug.print("{s}\n", .{m});
}

Key Takeaways