You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Zig ArrayList数组列表异常:遍历添加计数后数据出现错乱

问题根源与解决方案

核心问题:临时栈内存指针被覆盖

你的问题本质是错误地将迭代器返回的临时栈内存指针存入了ArrayList。Zig的std.fs.Dir.Iterator返回的entry.name指向迭代器内部的栈缓冲区,这块内存会在每次调用iter.next()时被覆盖;当栈帧布局变化(比如添加计数变量)时,还会被其他栈数据覆盖,导致后续读取到乱码。不加计数时只是侥幸栈内存未被覆盖,属于未定义行为,并非正确实现。

修复方案:复制文件名到堆内存

要解决这个问题,必须将筛选出的文件名复制到堆内存,再存入ArrayList,确保指针指向的内存不会被覆盖。以下是修正后的代码示例:

const std = @import("std");

fn get_specific_files(allocator: std.mem.Allocator, dir_path: []const u8, keyword: []const u8) ![]const []const u8 {
    var files = std.ArrayList([]const u8).init(allocator);
    defer files.deinit();

    const dir = try std.fs.cwd().openDir(dir_path, .{});
    defer dir.close();

    var iter = dir.iterate();
    var count: usize = 0; // 现在添加计数变量不会再导致乱码
    while (try iter.next()) |entry| {
        if (std.mem.indexOf(u8, entry.name, keyword) != null) {
            // 将文件名复制到堆内存,确保内存持久化
            const copied_name = try allocator.dupe(u8, entry.name);
            errdefer allocator.free(copied_name); // 异常时释放已分配的内存
            try files.append(copied_name);
            count += 1;
        }
    }

    return files.toOwnedSlice();
}

关键注意事项

  1. 内存释放责任:返回的切片中每个元素都是独立的堆分配内存,调用方需要先遍历切片释放每个文件名,再释放整个切片:
    const files = try get_specific_files(allocator, "./test", "keyword");
    defer {
        for (files) |file| allocator.free(file);
        allocator.free(files);
    }
    
  2. Zig与C的内存差异:和C不同,Zig的文件迭代器不会为文件名分配堆内存,所有临时数据都在栈上,因此必须手动复制到堆才能长期持有。
  3. errdefer的使用:添加errdefer确保在files.append失败时,已经分配的copied_name能被正确释放,避免内存泄漏。

内容的提问来源于stack exchange,提问作者fwamingo 273

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 13:52:34