How can I create multidimensional arrays of arbitrary sizes?

1.5k Views Asked by At

I am writing a function in Zig that should accept multidimensional arrays of arbitrary sizes. There can be limits but I am unable to hardcode the sizes in advance.

Here is an example:

const warn = @import("std").debug.warn;

fn printMap(map: []const [4]bool) void {
    for (map) |row| {
        for (row) |tile| {
            warn("{}\t", .{tile});
        }
        warn("\n", .{});
    }
}

pub fn main() !void {
    const map = [_][4]bool{
        [_]bool{ false, false, false, false },
        [_]bool{ false, true, true, false },
        [_]bool{ false, true, true, false },
        [_]bool{ false, false, false, false },
    };
    printMap(map[0..]);
}

This compiles and runs but if I change the function signature to

fn printMap(map: []const []bool) void

I receive the error

expected type '[]const []bool', found '[]const [4]bool'

Is this possible to express in Zig?

1

There are 1 best solutions below

1
On BEST ANSWER

Your map is declared as a multidimensional array [4][4]bool, and the length of an array is part of the compile time type (based on my understanding of https://ziglang.org/documentation/master/#Slices).

As you've figured out from printMap if you want these sizes to be defined at runtime, you'll have to use slices (types with a pointer and length) e.g. [][]bool

To get your example working using the signature printMap(map: []const []bool), you could do the following:

var a = [_]bool{ false, false, true };
var b = [_]bool{ false, true, false };

const map = [_][]bool{
    a[0..], // Make it a slice using slice syntax
    &b,     // Or make it a slice by coercing *[N]T to []T
};

var c: []const []bool = map[0..]; // Pass it as a slice of slices
printMap(c);

To create arrays of multidimensional slices of arbitrary sizes, you'd need to have some buffers to store the data. You could use some static memory, or allocate some as needed, one approach might be this:

fn buildMap(x: u8, y: u8, allocator: *std.mem.Allocator) ![][]bool {
    var map: [][]bool = undefined;
    map = try allocator.alloc([]bool, x);
    for (map) |*row| {
        row.* = try allocator.alloc(bool, y);
    }
    return map;
}

Which should work with printMap(map: []const []bool).

Another approach would be to use a single dimensional array/buffer, and index into it appropriately, but that doesn't quite answer your question. I'm fairly new to the language, so there might be subtleties I've missed.