How to initialize a 2D C pointer array

How can I properly initialize a 2D C pointer array? I try to initialize it as undefined and then after I pass it in and it compiles. But, when I try to then loop over it, it tells me:

main.zig:52:36: error: use of undefined value here causes undefined behavior
const r: [*c]u8 = image[i * pixel_size];
~^~~~~~~~~~~~

if I set it to null and it just segfaults. To do this in natively in C using the library is pretty easy you can just do the following:

    const char *filename = argv[1];
    unsigned error;
    unsigned char* image;
    unsigned width, height;

    error = lodepng_decode32_file(&image, &width, &height, filename);
    if (error) {
        fprintf(stderr, "Error %u: %s\n", error, lodepng_error_text(error));
        return EXIT_FAILURE;
    }

if I switch image to var from const, this and try to pass by reference this also doesn’t work? Anyone know what I am doing wrong here? Thanks in advance!

library I’m using:
https://github.com/lvandeve/lodepng

code for reference:

        var width: c_uint = 0;
        var height: c_uint = 0;
        var png: c_uint = 0;
        const image: [*c][*c]u8 = undefined;
        const pixel_size = 4; // RGBA
        png = c.lodepng_decode32_file(image, &width, &height, filename);
        if (png == 0) {
            std.debug.print("Error {d}: {s}\n", .{png, c.lodepng_error_text(png)});
            return;
        }

        var i: usize = 0;
        const zWidth: usize = @intCast(width);
        while (i < width * height) : (i += 1) {
            const r: [*c]u8 = image[i * pixel_size];
            const g: [*c]u8 = image[i * pixel_size + 1];
            const b: [*c]u8 = image[i * pixel_size + 2];
            const rf: f32 = @floatFromInt(@intFromPtr(r));
            const gf: f32 = @floatFromInt(@intFromPtr(g));
            const bf: f32 = @floatFromInt(@intFromPtr(b));
            const rgray: f32 = 0.299 * rf;
            const ggray: f32 = 0.587 * gf;
            const bgray: f32 = 0.114 * bf;
            const gray: u8 = @intFromFloat(rgray + ggray + bgray);
            const densityChar = density[gray * density.len / 256];
            try stdout.print("{c}", .{densityChar});
            if ((i + 1) % zWidth == 0) try stdout.print("\n", .{});
        }

translated zig function prototype:

pub extern fn lodepng_decode32_file(out: [*c][*c]u8, w: [*c]c_uint, h: [*c]c_uint, filename: [*c]const u8) c_uint;

runtime error:
Segmentation fault at address 0x0
/home/wizard/fun/zig/learn/tag/clib/lodepng.c:5431:8: 0x10213be in lodepng_decode32_file (lodepng.c)
*out = 0;
^
/home/wizard/fun/zig/learn/tag/src/main.zig:43:38: 0x102e842 in main (tag)
png = c.lodepng_decode32_file(image, &width, &height, filename);
^

The zig code equivalent of the C code is:

var image: [*c]u8 = undefined;
...
png = c.lodepng_decode32_file(&image, &width, &height, filename);
1 Like

Works! Why is it that I don’t have to actually pass in a 2D array on this one?

This is also going to work:

var image: [*c]u8 = undefined;
const image_ptr: [*c][*c]u8 = &image;
png = c.lodepng_decode32_file(image_ptr, &width, &height, filename);

We pass image_ptr that points to the var image.
The initial code image_ptr was not pointing to a variable, it was undefined.

2 Likes