hitakiri
@hitakiri

Как корректно передать данные из std.ArrayList в Slice?

Здравствуйте. Столкнулся со странным поведением структуры в zig. Точнее слайса ([]const u8) являющегося одним из элементов структуры, ниже пример.

const Statement = struct {
    content: []const u8,
};

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

    // allocator
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Read the text file by line
    var buf_reader = std.io.bufferedReader(script_file.reader());
    const reader = buf_reader.reader();

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

    var line_no: usize = 0;
    var statements: [26]Statement = undefined;  // в файле фиксированное количество строк

    while (reader.streamUntilDelimiter(line.writer(), '\n', null)) : (line_no += 1) {
        defer line.clearRetainingCapacity();

        var i: u16 = 0;

        // write content in statments
        for (line.items) |char| {
            if (char == ' ') {
                statements[line_no] = .{ .content = line.items[(i + 1)..] };
                break;
            }
            i += 1;
        }
        std.debug.print("State content -- {d}:\t {s}\n", .{ line_no, statements[line_no].content });  // тут statements[line_no].content выводит корректно
    } else |err| switch (err) {
        error.EndOfStream => {}, // Continue on
        else => std.debug.print("Ошибка при построчном чтении файла... {any}", .{err}), // Print error
    }

    inline for (statements) |s| {
        std.debug.print("State content len: {d}\n", .{s.content.len}); // корректно печатает длину слайса
        std.debug.print("State content ptr: {any}\n", .{s.content.ptr});  // печатает указатель на слайс
        std.debug.print("State content: {s}\n", .{s.content});    // здесь происходит ошибка:
        // State content: thread 13433 panic: reached unreachable code

    }


Т.е. компиляция проходит успешно, но обратиться к элементу структуры вне цыкла в котором были перенесины данные не получается. При том длину строки отображает корректно. Возможно кто-то сталкивался с таким?
Версия zig - 0.12.0-dev.2341+92211135f.
  • Вопрос задан
  • 57 просмотров
Решения вопроса 1
IvanU7n
@IvanU7n
nothing interesting here
-                statements[line_no] = .{ .content = line.items[(i + 1)..] };
+                statements[line_no] = .{ .content = try allocator.dupe(u8, line.items[(i + 1)..]) };

ну и не забыть очистить потом память

проблема в использовании одного и того же ArrayList в качестве буфера, да ещё и с очисткой после каждой итерации; понятное дело, что указатель будет не валидный после выходы из цикла
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
includedlibrary
@includedlibrary
Ну, как минимум, вы неправильно считываете строки.
while (reader.streamUntilDelimiter(line.writer(), '\n', null)) : (line_no += 1) {
        defer line.clearRetainingCapacity(); // по выходу из цикла буфер будет освобождён
        ...
        // тут вы для нескольких строк используете один и тот же буфер
       // даже если не освобождать память, у всех 26 структур будет указатель на один и тот же буфер, но
      // с разными смещениями
        statements[line_no] = .{ .content = line.items[(i + 1)..] };
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
29 нояб. 2024, в 09:43
100000 руб./за проект
29 нояб. 2024, в 07:44
20000 руб./за проект