Search code examples
zig

Malloc to a list of struct in Zig?


How can I dynamically allocate a memory space and get a pointer to a list of structs in Zig.

Like in C :

struct Foo* my_array_of_foo = (struct Foo*) malloc(10*sizeof(Foo));

Solution

  • const allocator: *std.mem.Allocator = std.heap.page_allocator; // this is not the best choice of allocator, see below.
    const my_slice_of_foo: []Foo = try allocator.alloc(Foo, 10);
    defer allocator.free(my_slice_of_foo);
    

    This will allocate a slice with len 10. It can later be freed with allocator.free(my_slice_of_foo)

    In zig, arrays are usually represented as slices which hold a pointer and the number of items (struct {ptr: [*]type, len: usize}). Allocators have a function .create(type) to allocate space for a single value and return a pointer, and a function .alloc(type, count) to allocate a contiguous array and return a slice.

    std.heap.page_allocator is not the best choice of an allocator for tasks like this. I would recommend using the general purpose allocator that will catch memory leaks for you, make it easier to find use-after-free errors, and use memory more efficiently:

    pub fn main() !void {
        var gpa = std.heap.GeneralPurposeAllocator(.{}){};
        defer std.debug.assert(!gpa.deinit());
        const allocator = &gpa.allocator;
    }
    

    In tests, it is good practice to use the testing allocator which offers the same safety features as the general purpose allocator but is handled for you by the test harness:

    test "allocate stuff" {
        const allocator = std.testing.allocator;
    }
    

    It is also often useful to create arena allocators. .free() does nothing on an arena allocator, instead everything put into an arena allocator gets freed all at once when the arena allocator is destroyed. This can make memory management easier and faster for sections of your application this works for.

    const allocator = ... pick an allocator;
    var arena_allocator = std.heap.ArenaAllocator.init(allocator);
    defer arena_allocator.deinit();
    const arena = &arena_allocator.allocator;