使用 ArrayList 和 Slices 时输出的不确定性

Non determinism in the output when using ArrayList and Slices

我正在与 Zig 一起研究代码的出现,现在是第 3 天。我已经上传了我编写的代码。拼图说明和代码在这里:https://github.com/secondspass/adventofcodeday3。代码在day3_part2.zig,输入文件在day3.in。我 运行 和 zig run day3_part2.zig.

当我 运行 代码时,我得到两个输出之一。 co2ScrubberRating 函数中的以下整数溢出。

thread 174927 panic: integer overflow
/home/subil/Projects/zig_learn/adventofcode/test/day3_part2.zig:80:25: 0x23401c in co2ScrubberRating (day3_part2)
    while (i >= 0) : (i -= 1) {
                        ^
/home/subil/Projects/zig_learn/adventofcode/test/day3_part2.zig:112:42: 0x22c80e in main (day3_part2)
    var co2rating = try co2ScrubberRating(numbers.items[0..], allocator);
                                         ^
/home/subil/tools/zig-0.9.0/lib/std/start.zig:535:37: 0x224eaa in std.start.callMain (day3_part2)
            const result = root.main() catch |err| {
                                    ^
/home/subil/tools/zig-0.9.0/lib/std/start.zig:477:12: 0x208ace in std.start.callMainWithArgs (day3_part2)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/home/subil/tools/zig-0.9.0/lib/std/start.zig:391:17: 0x207b56 in std.start.posixCallMainAndExit (day3_part2)
    std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
                ^
/home/subil/tools/zig-0.9.0/lib/std/start.zig:304:5: 0x207962 in std.start._start (day3_part2)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    ^
Aborted (core dumped)

否则我会得到以下输出,其中第二行的二进制数是 co2ScrubberRating 函数的输出是一个看似随机的数。

100111011110
1000000111101101010111 

每次我 运行 zig run day3_part2.zig.

我得到的输出是随机的

我将相同的 ArrayList.items 切片和分配器传递给 oxygenGeneratorRatingco2ScrubberRating。如果我在 main 中只 运行 这些函数之一(即我注释掉其中一个),则会为该函数生成正确的输出。但是如果我在 main 中同时拥有这两个函数,我会从 co2ScrubberRating 函数中得到随机的错误输出。而且我不知道为什么它会这样。我想这与第二次将 ArrayList 传递给函数有关。

如有任何见解,我们将不胜感激。

这是因为 readToNumberList 正在返回指向超出范围的堆栈内存的指针,这是未定义的行为并且尚未在调试版本中捕获。

fn readNumberList(…) !*std.ArrayList(u32) {
    …
    return &numbers;

将代码更改为

fn readNumberList(…) !std.ArrayList(u32) {
    …
    return numbers;

修复了问题。

您也可以通过将 ArrayList 结构放入堆内存来修复它:

fn readNumberList(…) !*std.ArrayList(u32) {
    const numbers = try allocator.create(std.ArrayList(u32));
    numbers.* = std.ArrayList(u32).init(allocator);
    …
    return numbers;

添加到 pfg 的回复中,wrt while (i >= 0) : (i -= 1) {...},这确实是一个循环,如果 i 未签名,则在到达末尾时会下溢。在最后一次迭代结束时,当i == 0时,循环将尝试最后一次减去,导致下溢。

解决办法是把条件改成i > 0,在体内做减法,作为第一个运算

while (i > 0) {
   i -= 1;
   // ...
}