0

I've been going through ziglearn and have made my way to ArrayList. I understand the example given there but when I try something a bit more complex I run into errors. Based on the error it seems like my array doesn't have valid memory when it goes to append the new element, but I've set the initial capacity to 10. What am I doing wrong?

const std = @import("std");
const page_allocator = std.heap.page_allocator;
const Allocator = std.mem.Allocator;

const C = struct {
    list: std.ArrayList(A),
    pub fn init(allocator: Allocator) !*C {
        var a = try std.ArrayList(A).initCapacity(allocator, 10);
        return &C{ .list = a };
    }
    pub fn info(self: *C) void {
        std.log.info("len {}  cap {}", .{ self.list.items.len, self.list.capacity });
    }
    pub fn addElement(self: *C, a: A) !*C {
        try self.list.append(a);
        return self;
    }
};
const A = struct { e: []const u8 };

test "with arraylist" {
    var foo = try C.init(page_allocator);
    foo.info();
    _ = try foo.addElement(.{ .e = "bar" });
}

Can see below the initial capacity is not 10, it changes with each run pointing to its uninitialized. Am I missing a step to initialize memory for the ArrayList?

[default] (info): len 0  cap 140728248984328
Segmentation fault at address 0x0
/home/john/zig/zig-linux-x86_64-0.10.0/lib/std/mem/Allocator.zig:159:30: 0x219c3c in reallocAdvancedWithRetAddr__anon_4653 (test)
    return self.vtable.resize(self.ptr, buf, buf_align, new_len, len_align, ret_addr);
                             ^
/home/john/zig/zig-linux-x86_64-0.10.0/lib/std/mem/Allocator.zig:356:43: 0x216faf in reallocAtLeast__anon_3534 (test)
    return self.reallocAdvancedWithRetAddr(old_mem, old_alignment, new_n, .at_least, @returnAddress());
                                          ^
/home/john/zig/zig-linux-x86_64-0.10.0/lib/std/array_list.zig:353:89: 0x215697 in ensureTotalCapacityPrecise (test)
                const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), new_capacity);
                                                                                        ^
/home/john/zig/zig-linux-x86_64-0.10.0/lib/std/array_list.zig:338:55: 0x2170f6 in ensureTotalCapacity (test)
                return self.ensureTotalCapacityPrecise(better_capacity);
                                                      ^
/home/john/zig/zig-linux-x86_64-0.10.0/lib/std/array_list.zig:377:41: 0x21577c in addOne (test)
            try self.ensureTotalCapacity(newlen);
                                        ^
/home/john/zig/zig-linux-x86_64-0.10.0/lib/std/array_list.zig:167:49: 0x213c16 in append (test)
            const new_item_ptr = try self.addOne();
                                                ^
src/main.zig:154:29: 0x213b86 in addElement (test)
        try self.list.append(a);
                            ^
src/main.zig:165:27: 0x213ce7 in test.with arraylist (test)
    _ = try foo.addElement(.{ .e = "bar" });
                          ^
/home/john/zig/zig-linux-x86_64-0.10.0/lib/test_runner.zig:63:28: 0x2164f0 in main (test)
        } else test_fn.func();
                           ^
/home/john/zig/zig-linux-x86_64-0.10.0/lib/std/start.zig:596:22: 0x21463b in posixCallMainAndExit (test)
            root.main();
                     ^
/home/john/zig/zig-linux-x86_64-0.10.0/lib/std/start.zig:368:5: 0x214101 in _start (test)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    ^
dangeroushobo
  • 1,291
  • 2
  • 16
  • 28

1 Answers1

2

Your C.init function returns a pointer to C which is on the stack of the init function. This pointer becomes invalid as soon as the function exits.

Just don't return it as a pointer:

pub fn init(allocator: Allocator) !C {
    var a = try std.ArrayList(A).initCapacity(allocator, 10);
    return C{ .list = a };
}

Or, alternatively, you could put C into the allocator's memory:

pub fn init(allocator: Allocator) !*C {
    var result = try allocator.create(C);
    result.list = try std.ArrayList(A).initCapacity(allocator, 10);
    return result;
}

But avoid doing this unless you have a good reason, as it limits what you can do with C.

sigod
  • 3,514
  • 2
  • 21
  • 44