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(); }
关键注意事项
- 内存释放责任:返回的切片中每个元素都是独立的堆分配内存,调用方需要先遍历切片释放每个文件名,再释放整个切片:
const files = try get_specific_files(allocator, "./test", "keyword"); defer { for (files) |file| allocator.free(file); allocator.free(files); } - Zig与C的内存差异:和C不同,Zig的文件迭代器不会为文件名分配堆内存,所有临时数据都在栈上,因此必须手动复制到堆才能长期持有。
- errdefer的使用:添加
errdefer确保在files.append失败时,已经分配的copied_name能被正确释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者fwamingo 273
相关产品推荐
相关产品推荐

