iterate over multi dimensional array passed into function

75 views Asked by At

I've successfully passed iterable 1d arrays into a function like this

const std = @import("std");

pub fn loopArray(arr: []u8) void {
    for (arr, 0..) |elem, i| {
        std.debug.print("array at {d} = {d}", .{ i, elem });
    }
}

var foo: [4]u8 = .{ 4, 3, 2, 8 };

pub fn main() void {
    loopArray(&foo);
}

but when I try to extend it to multiple dimensions

pub fn loopArray2(arr: [][]u8) void {
    for (arr, 0..) |row, j| {
        for (row, 0..) |elem, i| {
            std.debug.print("array at {d},{d} = {d}", .{ j, i, elem });
        }
    }
}
var foo: [4]u8 = .{ 4, 3, 2, 8 };
var bar: [2][4]u8 = .{ .{ 4, 3, 2, 8 }, .{ 4, 3, 2, 8 } };

pub fn main() void {
    loopArray2(&bar);
}

i get this error:

arrayLoop.zig:21:16: error: expected type '[][]u8', found '*[2][4]u8'
    loopArray2(&bar);

one way I managed to do this is by marking it as anytype but that's not ideal as I want stricter typing on my function

pub fn loopArray2(arr: anytype) void {
    for (arr, 0..) |row, j| {
        for (row, 0..) |elem, i| {
            std.debug.print("array at {d},{d} = {d}", .{ j, i, elem });
        }
    }
}
1

There are 1 answers

0
pfg On BEST ANSWER

This is because of the difference between [n]u8, a value type and []u8, a slice type representing a pointer and a length.

[2][4]u8 represents a single contiguous region of memory 8 bytes long. [][]u8 represents a slice of slices where each slice contains a pointer and a length. A slice is equivalent to struct {ptr: [*]u8, len: usize}. [*]u8 is an indexable pointer with an unknown length.

You can solve it by making an array of slices, like this:

pub fn loopArray2(arr: []const []const u8) void {
    for (arr, 0..) |row, j| {
        for (row, 0..) |elem, i| {
            std.debug.print("array at {d},{d} = {d}", .{ j, i, elem });
        }
    }
}
const foo: []const u8 = &[_]u8{ 4, 3, 2, 8 };
const bar: []const []const u8 = &[_]u8{ &[_]{ 4, 3, 2, 8 }, &[_]{ 4, 3, 2, 8 } };

This will no longer be a contiguous region of memory like [2][4]u8 is, instead it is a two-len slice holding two four-len slices.

If you want a contiguous region of memory, you can simulate a 2d array with a 1d array (ie const bar: [8]u8 = .{4, 3, 2, 8, 4, 3, 2, 8};)