Arrays

Arrays

arrays.zig

const expect = @import("std").testing.expect;
const assert = @import("std").debug.assert;
const mem = @import("std").mem;

// array literal
const message = [_]u8{ 'h', 'e', 'l', 'l', 'o' };

// get the size of an array
comptime {
    assert(message.len == 5);
}

// A string literal is a single-item pointer to an array literal.
const same_message = "hello";

comptime {
    assert(mem.eql(u8, &message, same_message));
}

test "iterate over an array" {
    var sum: usize = 0;
    for (message) |byte| {
        sum += byte;
    }
    try expect(sum == 'h' + 'e' + 'l' * 2 + 'o');
}

// modifiable array
var some_integers: [100]i32 = undefined;

test "modify an array" {
    for (some_integers) |*item, i| {
        item.* = @intCast(i32, i);
    }
    try expect(some_integers[10] == 10);
    try expect(some_integers[99] == 99);
}

// array concatenation works if the values are known
// at compile time
const part_one = [_]i32{ 1, 2, 3, 4 };
const part_two = [_]i32{ 5, 6, 7, 8 };
const all_of_it = part_one ++ part_two;
comptime {
    assert(mem.eql(i32, &all_of_it, &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }));
}

// remember that string literals are arrays
const hello = "hello";
const world = "world";
const hello_world = hello ++ " " ++ world;
comptime {
    assert(mem.eql(u8, hello_world, "hello world"));
}

// ** does repeating patterns
const pattern = "ab" ** 3;
comptime {
    assert(mem.eql(u8, pattern, "ababab"));
}

// initialize an array to zero
const all_zero = [_]u16{0} ** 10;

comptime {
    assert(all_zero.len == 10);
    assert(all_zero[5] == 0);
}

// use compile-time code to initialize an array
var fancy_array = init: {
    var initial_value: [10]Point = undefined;
    for (initial_value) |*pt, i| {
        pt.* = Point{
            .x = @intCast(i32, i),
            .y = @intCast(i32, i) * 2,
        };
    }
    break :init initial_value;
};
const Point = struct {
    x: i32,
    y: i32,
};

test "compile-time array initialization" {
    try expect(fancy_array[4].x == 4);
    try expect(fancy_array[4].y == 8);
}

// call a function to initialize an array
var more_points = [_]Point{makePoint(3)} ** 10;
fn makePoint(x: i32) Point {
    return Point{
        .x = x,
        .y = x * 2,
    };
}
test "array initialization with function calls" {
    try expect(more_points[4].x == 3);
    try expect(more_points[4].y == 6);
    try expect(more_points.len == 10);
}

Shell

$ zig test arrays.zig
1/4 test "iterate over an array"... OK
2/4 test "modify an array"... OK
3/4 test "compile-time array initialization"... OK
4/4 test "array initialization with function calls"... OK
All 4 tests passed.

See also:

  • for
  • Slices

Anonymous List Literals

Similar to Enum Literals and Anonymous Struct Literals the type can be omitted from array literals:

anon_list.zig

const std = @import("std");
const expect = std.testing.expect;

test "anonymous list literal syntax" {
    var array: [4]u8 = .{11, 22, 33, 44};
    try expect(array[0] == 11);
    try expect(array[1] == 22);
    try expect(array[2] == 33);
    try expect(array[3] == 44);
}

Shell

$ zig test anon_list.zig
1/1 test "anonymous list literal syntax"... OK
All 1 tests passed.

If there is no type in the result location then an anonymous list literal actually turns into a struct with numbered field names:

infer_list_literal.zig

const std = @import("std");
const expect = std.testing.expect;

test "fully anonymous list literal" {
    try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi"});
}

fn dump(args: anytype) !void {
    try expect(args.@"0" == 1234);
    try expect(args.@"1" == 12.34);
    try expect(args.@"2");
    try expect(args.@"3"[0] == 'h');
    try expect(args.@"3"[1] == 'i');
}

Shell

$ zig test infer_list_literal.zig
1/1 test "fully anonymous list literal"... OK
All 1 tests passed.

Multidimensional Arrays

Multidimensional arrays can be created by nesting arrays:

multidimensional.zig

const std = @import("std");
const expect = std.testing.expect;

const mat4x4 = [4][4]f32{
    [_]f32{ 1.0, 0.0, 0.0, 0.0 },
    [_]f32{ 0.0, 1.0, 0.0, 1.0 },
    [_]f32{ 0.0, 0.0, 1.0, 0.0 },
    [_]f32{ 0.0, 0.0, 0.0, 1.0 },
};
test "multidimensional arrays" {
    // Access the 2D array by indexing the outer array, and then the inner array.
    try expect(mat4x4[1][1] == 1.0);

    // Here we iterate with for loops.
    for (mat4x4) |row, row_index| {
        for (row) |cell, column_index| {
            if (row_index == column_index) {
                try expect(cell == 1.0);
            }
        }
    }
}

Shell

$ zig test multidimensional.zig
1/1 test "multidimensional arrays"... OK
All 1 tests passed.

Sentinel-Terminated Arrays

The syntax [N:x]T describes an array which has a sentinel element of value x at the index corresponding to len.

null_terminated_array.zig

const std = @import("std");
const expect = std.testing.expect;

test "null terminated array" {
    const array = [_:0]u8 {1, 2, 3, 4};

    try expect(@TypeOf(array) == [4:0]u8);
    try expect(array.len == 4);
    try expect(array[4] == 0);
}

Shell

$ zig test null_terminated_array.zig
1/1 test "null terminated array"... OK
All 1 tests passed.

See also:

  • Sentinel-Terminated Pointers
  • Sentinel-Terminated Slices