I am modifying the value referenced by a const pointer and I don't know why

Hello, I am working on a small weighted graph struct to learn zig. I want to build an iterator over all edges. See the edgeIter function and the related EdgeIter struct. Something weird happen when I call the next function of EdgeIter. I added a few print statements to show that the lengths of the two ArrayLists are changed but I don’t understand why since graph is a constant pointer and I am not updating it anywhere.

const std = @import("std");
const ArrayList = std.ArrayList;

pub const Graph = struct {
    nodes: ArrayList(f32),
    edges: ArrayList(f32),

    pub fn init(allocator: std.mem.Allocator, num: usize) !Graph {
        var nodes = try ArrayList(f32).initCapacity(allocator, num);
        nodes.appendNTimesAssumeCapacity(0.0, num);
        var edges = try ArrayList(f32).initCapacity(allocator, num * (num - 1) / 2);
        edges.appendNTimesAssumeCapacity(0.0, num * (num - 1) / 2);
        return .{
            .nodes = nodes,
            .edges = edges,
        };
    }

    pub fn deinit(graph: Graph) void {
        graph.nodes.deinit();
        graph.edges.deinit();
    }

    pub fn numNodes(graph: Graph) usize {
        return graph.nodes.items.len;
    }

    pub fn edgeIter(graph: Graph) EdgeIter {
        return EdgeIter{ .graph = &graph, .index = 0, .first = 0, .second = 1 };
    }
};

pub const Edge = struct {
    first: usize,
    second: usize,
    value: f32,
};

pub const EdgeIter = struct {
    graph: *const Graph,
    index: usize,
    first: usize,
    second: usize,

    pub fn next(self: *EdgeIter) ?Edge {
        std.debug.print("\n------------\n", .{});
        std.debug.print("nodes.items.len = {}\n", .{self.graph.nodes.items.len});
        std.debug.print("edges.items.len = {}\n", .{self.graph.edges.items.len});
        if (self.index >= self.graph.edges.items.len) {
            return null;
        }
        const edge = Edge{
            .first = self.first,
            .second = self.second,
            .value = self.graph.edges.items[self.index],
        };
        self.index += 1;
        self.second += 1;
        if (self.second == self.graph.numNodes()) {
            self.first += 1;
            self.second = self.first + 1;
        }
        return edge;
    }
};

pub fn main() !void {
    const alloc = std.heap.page_allocator;
    const graph = try Graph.init(alloc, 4);
    defer graph.deinit();
    var iter = graph.edgeIter();
    while (iter.next()) |edge| {
        _ = edge;
    }
}

For reference, this is the output I get

------------
nodes.items.len = 4
edges.items.len = 6

------------
nodes.items.len = 140728799473088
edges.items.len = 0

Also, if I try to print the actual items instead of items.len I get a segmentation fault.

You are assigning reference to a temporary value.
Instead change the function argument to graph: *const Graph and assign it directly.

1 Like

Wow thank you. That was an easy solution.