如何在页面模板中访问特定分类法?文章标签渲染失败排查
Zig词频统计程序:编译错误与越界panic解决指南
问题描述
我用Zig编写了一个统计文本文件单词出现次数的程序,但遇到两个问题:
- 编译时抛出错误:
error: expected type '*void', found '*const void' - 修复编译错误后,运行时触发panic:
panic: index out of bounds
原始代码如下:
const std = @import("std"); const print = std.debug.print; pub fn main() !void { const allocator = std.heap.page_allocator; // 读取文件内容 const file = try std.fs.cwd().openFile("input.txt", .{}); defer file.close(); const content = try file.readToEndAlloc(allocator, 1024 * 1024); defer allocator.free(content); // 分割成单词 var words = std.mem.tokenizeAny(u8, content, " \n\t.,!?;:'\"()[]{}"); var hash_map = std.StringHashMap(usize).initCapacity(allocator, 100) catch unreachable; defer hash_map.deinit(); var counts = std.ArrayListUnmanaged(u32).initCapacity(allocator, 100) catch unreachable; defer counts.deinit(allocator); while (words.next()) |word| { if (hash_map.get(word)) |index| { counts.items[index] += 1; } else { hash_map.putAssumeCapacity(word, counts.items.len); counts.appendAssumeCapacity(1); } } // 打印结果 var iterator = hash_map.iterator(); while (iterator.next()) |entry| { const word = entry.key_ptr.*; const count = counts.items[entry.value_ptr.*]; print("{s}: {d}\n", .{word, count}); } }
问题分析与解决方案
1. 编译错误修复
错误原因:std.ArrayListUnmanaged(u32).initCapacity要求传入*std.mem.Allocator(可变指针),但std.heap.page_allocator是*const std.mem.Allocator(常量指针),类型不匹配导致编译失败。
解决方法:
改用std.ArrayList替代ArrayListUnmanaged。std.ArrayList是带allocator管理的容器,初始化方法接受*const Allocator,且自动处理内存扩容逻辑,无需手动管理容量。
2. 运行时越界panic修复
错误原因:
原始代码使用putAssumeCapacity和appendAssumeCapacity,这两个方法强制假设容器已有足够容量,当单词数量超过初始化的100容量时,会直接触发内存越界panic。
解决方法:
将putAssumeCapacity替换为try hash_map.put(...),appendAssumeCapacity替换为try counts.append(...)。这两个方法会自动检查容器容量,不足时自动扩容,彻底避免越界问题。
修正后的完整代码
const std = @import("std"); const print = std.debug.print; pub fn main() !void { const allocator = std.heap.page_allocator; // 读取文件内容 const file = try std.fs.cwd().openFile("input.txt", .{}); defer file.close(); const content = try file.readToEndAlloc(allocator, 1024 * 1024); defer allocator.free(content); // 分割成单词 var words = std.mem.tokenizeAny(u8, content, " \n\t.,!?;:'\"()[]{}"); var hash_map = std.StringHashMap(usize).init(allocator); defer hash_map.deinit(); var counts = std.ArrayList(u32).init(allocator); defer counts.deinit(); while (words.next()) |word| { if (hash_map.get(word)) |index| { counts.items[index] += 1; } else { try hash_map.put(word, counts.items.len); try counts.append(1); } } // 打印结果 var iterator = hash_map.iterator(); while (iterator.next()) |entry| { const word = entry.key_ptr.*; const count = counts.items[entry.value_ptr.*]; print("{s}: {d}\n", .{word, count}); } }
额外注意事项
- 如果确定单词数量不会超过初始容量(如100),可以保留
initCapacity初始化容器,但必须确保后续操作不会超出容量,否则仍会触发panic。 readToEndAlloc的第二个参数是最大读取字节数,若处理大文件需适当调整该值。- 所有分配的内存都通过
defer语句释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者佚名
相关产品推荐
相关产品推荐

