How to copy a string in Zig?

I’m trying to send all the values from a filetext to an ArrayList, but I’ve noticed that the values end up always being duplicated, and it’s probably cuz the pointers to the variable are changing in each loop line.

How do I fix that? I’ve thought about copying the string, but got no solution, I’ve tried the std.mem.copy method, the @memcpy builtin function and line[…line.len], but my inexperience in C/Zig is showing :P, here’s the code:

const allocator = std.heap.page_allocator;

var list = ArrayList([]const u8).init(allocator);
defer list.deinit();

var file = try std.fs.cwd().openFile("src/input.txt", .{});
defer file.close();

var buf_reader = std.io.bufferedReader(file.reader());
var buf: [1024]u8 = undefined;

while (try buf_reader.reader().readUntilDelimiterOrEof(&buf, '\n')) |line| {
    try list.append(std.mem.trim(u8, line, "\r"));
}

The problem is you are working with slices instead of arrays that “own” their own memory. A slice is a pointer with a length to an array. You are storing slices to that same array in multiple places.

  • edited *

To be more helpful, if you want to have dynamically resizable strings, you could use an ArrayList(u8) for each element in your list (they would act like resizable strings at that point). Or you could have buffers that each are long enough to contain whatever string you want.

1 Like

Using the ArrayList(u8) alternative, I would need to copy each value(byte) individually, right?

Let’s have a look at the API of the standard library here and see if you find what you need: zig/lib/std/array_list.zig at master · ziglang/zig · GitHub

One option is you could do an appendSlice and make it very similar to what you are doing now:

    /// Append the slice of items to the list. Allocates more
        /// memory as necessary.
        /// Invalidates pointers if additional memory is needed.
        pub fn appendSlice(self: *Self, items: []const T) Allocator.Error!void {
            try self.ensureUnusedCapacity(items.len);
            self.appendSliceAssumeCapacity(items);
        }
1 Like

If this works for you, can you mark it as a solution so the forum can see that the question was answered?

Doing something like this worked for me:

const allocator = std.heap.page_allocator;

var list = ArrayList(ArrayList(u8)).init(allocator);
defer list.deinit();

var file = try std.fs.cwd().openFile("src/input.txt", .{});
defer file.close();

var buf_reader = std.io.bufferedReader(file.reader());
var buf: [1024]u8 = undefined;

while (try buf_reader.reader().readUntilDelimiterOrEof(&buf, '\n')) |line| {
    var value = ArrayList(u8).init(allocator);
    try value.appendSlice(std.mem.trim(u8, line, "\r"));
    try list.append(value);
}

Copy a string: std.mem.Allocator.dupe

Read entire file into byte buffer: std.fs.Dir.readFileAlloc

Related: std.io.Reader.readUntilDelimiterArrayList

5 Likes