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

如何在页面模板中访问特定分类法?文章标签渲染失败排查

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,提问作者佚名

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:24:53