splitAny returns garbage

Hi there! I’m new to zig, and stumbled upon something I don’t understand. I want to simply split console line input by spaces and store the result in an arrayList. However, this is the result produced (first line is input):

F 1 200 F 2 170 B 1 200 B 2 100
In: F 1 200 F 2 170 B 1 200 B 2 100
split input: F 1 200 F 2 170 B 1 200
Iterator element content: { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }
Return list content (element-wise): { 1 }  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }

I don’t understand why the iterator content is what it is. The split method works just fine in tests.

This is the code (I removed most unnessecary parts):


fn johnny() !void {
    const msg: []const u8 = try lib.readLine() orelse "somehow nothing was read. Deal with it.";
    
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = arena.allocator();
    
    const result = try checkJohn(allocator, msg);
    defer result.deinit();
    
    // irrelevant parts
}

fn checkJohn(allocator: std.mem.Allocator, check_list: []const u8) !std.ArrayList(u32) {
    std.debug.print("In: {s}\n", .{check_list});
    
    var check_items = std.ArrayList([]const u8).init(allocator);
    defer check_items.deinit();
    try split(&check_items, check_list, " ");
    const items = check_items.items;
    
    std.debug.print("Split: \n", .{});
    for (check_items.items) |item| {
        std.debug.print("{x} {s} ", .{item, item});
    }
    std.debug.print("\n", .{});
    // irrelevant parts
}

fn split(list: *std.ArrayList([]const u8), msg: []const u8, delimiter: []const u8) !void {
    std.debug.print("split input: {s}\n", .{msg});
    var iterator = std.mem.splitAny(u8, msg, delimiter);
    try list.append(iterator.first());
    std.debug.print("Iterator element content: ", .{});
    while (iterator.next()) |elem| {
        std.debug.print("{x} {s} ", .{elem, elem});
        try list.append(elem);
    }
    std.debug.print("\nReturn list content (element-wise): ", .{});
    for (list.items) |item| {
        std.debug.print("{x} {s} ", .{item, item});
    }
    std.debug.print("\n", .{});
}


test "Split test" {
    var expected = std.ArrayList([]const u8).init(std.testing.allocator);
    defer expected.deinit();
    try expected.append("F");
    try expected.append("1");
    try expected.append("100");
    try expected.append("📷click");
    
    var actual = std.ArrayList([]const u8).init(std.testing.allocator);
    defer actual.deinit();
    try split(&actual, "F 1 100 📷click", " ");
    
    try testing.expectEqual(expected.items.len, actual.items.len);
}

How did you allocate the input string?
Have you tried printing the input string again after the split operations?

const msg: []const u8 = try lib.readLine()

This looks suspiciously like readLine might be returning a slice of a stack-allocated buffer (which goes out-of-scope when readLine returns), since it’s neither taking a buffer nor an Allocator as input.

2 Likes