# Casting to a C array of strings

**URL:** <https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872>\
**Category:** Help\
**Tags:** language, c, string\
**Created:** [March 4, 2025, 4:10pm UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872 "2025-03-04T16:10:44Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![videbar](https://ziggit.dev/letter_avatar_proxy/v4/letter/v/e480ec/32.png) [@videbar](https://ziggit.dev/u/videbar)\
**Post date:** [March 4, 2025, 4:10pm UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/1 "2025-03-04T16:10:44Z")

</div>

Hi everyone,

I’m currently building a zig project and I depend on a C library. One of the functions of the library takes as a parameter an array of strings, i.e., an array of pointers terminated with a null pointer (the array), each element of the array being a `char` pointer (a null-terminated string).

As an example, the function can take an argument like this:

```c
char *strings[] = {"foo", "bar", NULL};
string_hungy_func((const char * const *) strings);

```

Now, I’ve struggling a lot to understand how I can cast a zig type to be used with this function. As a far as I understand, I need a null-terminated many-item pointer to null-terminated pointers to `u8`, so I’ve tried doing this:

```zig
const string_list: [*:null]const ?[*:0]const u8 = @alignCast(@ptrCast(&.{ &.{"Foo"}, &.{"Bar"}, null }));
const list = string_hungy_func(@ptrCast(string_list)));

```

Which pleases the compiler, but results in a segmation fault.

Can you explain to me how I could properly cast the arguments to this function?

Thanks!

---

<div class="post-metadata">

**Author:** ![Southporter](https://ziggit.dev/user_avatar/ziggit.dev/southporter/32/2500_2.png) [@Southporter](https://ziggit.dev/u/Southporter)\
**Post date:** [March 4, 2025, 4:20pm UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/2 "2025-03-04T16:20:50Z")

</div>

Have you linked libc in your application? I ran into an issue the other day where I was intracting with a c library but forgot to link libc and kept getting a segfault at address 0x0. I think this is a segfault calling the library’s functions. That may be what is happening here.

---

<div class="post-metadata">

**Author:** ![IceGuye](https://ziggit.dev/letter_avatar_proxy/v4/letter/i/b782af/32.png) [@IceGuye](https://ziggit.dev/u/IceGuye)\
**Post date:** [March 4, 2025, 4:55pm UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/3 "2025-03-04T16:55:48Z")

</div>

Zig’s null-terminated array initiating does NOT need the last null. Zig’s null-terminated array’s len field (`my_array.len`) will return the same len as how many “actual” items you have, and will not include the last null. So you don’t do anything with last null in your codes… The compiler will do the job for you. See here: [https://ziglang.org/documentation/master/#Sentinel-Terminated-Arrays](https://ziglang.org/documentation/master/#Sentinel-Terminated-Arrays)

This should work:

```zig
const string_list = [_:null]?[*:0]const u8 {"foo", "bar"};
const list = string_hungy_func(&string_list);

```

I had a similar discussion another day here: [https://ziggit.dev/t/how-to-handle-c-const-c-const-u8-in-a-c-library/8768](https://ziggit.dev/t/how-to-handle-c-const-c-const-u8-in-a-c-library/8768)

---

<div class="post-metadata">

**Author:** ![videbar](https://ziggit.dev/letter_avatar_proxy/v4/letter/v/e480ec/32.png) [@videbar](https://ziggit.dev/u/videbar)\
**Post date:** [March 5, 2025, 10:15am UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/4 "2025-03-05T10:15:40Z")

</div>

Thanks! That’s kind of what I was looking for. Just out of curiosity, how could one deal  
with strings allocated dynamically at runtime, i.e., how does one cast a `[][]const u8`  
to a `[:null]?[*:0]const u8`?

I’ve tried the following:

```zig
    var str_list: [][]const u8 = undefined;

    const n_strings = 2;
    const string_len = 4;

    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    const allocator = arena.allocator();
    str_list = try allocator.alloc([]u8, n_strings);
    defer {
        allocator.free(str_list);
    }

    for (0..n_strings) |i| {
        const str = try allocator.alloc(u8, string_len);

        for (0..string_len) |j| {
            str[j] = 'a';
        }
        str_list[i] = str;
    }
    defer {
        for (0..n_strings) |i| {
            allocator.free(str_list[i]);
        }
    }
    // Here's how I'm trying to do the casting:
    const c_str_list: [:null]?[*:0]const u8 = @ptrCast(str_list); 
    _ = c_str_list;

```

But the compiler throws the error:

```zig
error: TODO: implement @ptrCast between slices changing the length

```

Which makes me think that I’m doing something wrong, but I’m not sure how to handle it.

---

<div class="post-metadata">

**Author:** ![IceGuye](https://ziggit.dev/letter_avatar_proxy/v4/letter/i/b782af/32.png) [@IceGuye](https://ziggit.dev/u/IceGuye)\
**Post date:** [March 5, 2025, 4:20pm UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/5 "2025-03-05T16:20:23Z")

</div>

Make your first allocation

> [@videbar](#):
>
> ```zig
> str_list = try allocator.alloc([]u8, n_strings);
> 
> ```

to this:

```zig
str_list = try allocator.alloc([*:0]const u8, n_strings);

```

This should do the trick.

I actually played around about this on my own codes after I saw your post.

See here: [https://gitlab.com/IceEternityProject/IceWindowing/-/blob/ef0e93a9150468cd06c466c861302e8003078897/Wayland/src/root.zig#L287](https://gitlab.com/IceEternityProject/IceWindowing/-/blob/ef0e93a9150468cd06c466c861302e8003078897/Wayland/src/root.zig#L287)

and here: [https://gitlab.com/IceEternityProject/IceWindowing/-/blob/ef0e93a9150468cd06c466c861302e8003078897/Wayland/src/root.zig#L342](https://gitlab.com/IceEternityProject/IceWindowing/-/blob/ef0e93a9150468cd06c466c861302e8003078897/Wayland/src/root.zig#L342)

By the way, I use the master version of zig, well anyways 0.14.0 was just released today.

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [March 6, 2025, 1:20am UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/6 "2025-03-06T01:20:56Z")

</div>

> [@IceGuye](#):
>
> `str_list = try allocator.alloc([*:0]const u8, n_strings);`

makes a `[][*:0]const u8`  
to get [:null]?[\*:0]const u8` do:

```zig
const str_list = try allocator.allocSentinal(?[*:0]const u8, n_strings, null);

```

_there is no reason to create a `undefined` var first_

note that `str_list` can be a slice, but the strings inside it have to be many item pointers.

you also need to change allocating the string in the loop to

```zig
const str = try allocator.allocSentinal(u8, string_len, 0);

```

note that I am creating the types instead of casting them

You shouldn’t cast a non terminated slice/mip to a terminated slice/mip. _mip being a many item pointer_

You can’t cast `[][]const u8` to a `[:null]?[*:0]const u8` as the item types have different sizes.

A slice is essentially `struct { ptr: [*]T, len:usize}`  
_note that optional pointers have the same size as non-optional pointers due to an optimisation, but that’s irrelevant atm_

---

<div class="post-metadata">

**Author:** ![videbar](https://ziggit.dev/letter_avatar_proxy/v4/letter/v/e480ec/32.png) [@videbar](https://ziggit.dev/u/videbar)\
**Post date:** [March 6, 2025, 11:11am UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/7 "2025-03-06T11:11:54Z")

</div>

Thanks for your answers, they’ve been really useful for me to understand how the type system, the different types of pointers and the sentinels all go together.

However, what I meant was, if I have a C function that takes an array of strings (`const char *const *`) and a zig function that returns a dynamically-allocated list of strings (`[][]const u8`), how can I pass the former to the latter?

I have built this example in which I allocate a new copy of the string in a way that can be understood by the C function, but I wonder if there’s a better way to do it:

This is my C code:

```c
#include <stdio.h>
void printStringList(const char *const *list) {
    for (int i = 0; list[i]; i++) {
        for (int j = 0; list[i][j]; j++) {
            printf("%c", list[i][j]);
        }
        printf("\n");
    }
}

```

And I have this zig function that returns a slice of strings:

```zig
fn generateStrings(allocator: std.mem.Allocator) ![][]const u8 {
    const n_strings = 2;
    const string_len = 4;

    var str_list: [][]const u8 = try allocator.alloc([]const u8, n_strings);

    for (0..n_strings) |i| {
        const str: []u8 = try allocator.alloc(u8, string_len);

        for (0..string_len) |j| {
            str[j] = 'a';
        }
        str_list[i] = str;
    }

    return str_list;
}

```

What I want to do if feed the output of `generateStrings()` into `printStringList()`, but the problem is that `printStringList()` expects a null terminator in each string and in the array containing the strings. Because the array and the strings are dynamically allocated, this requires allocating new memory.

Also (I may be wrong on this, please correct me if that’s the case), since I’m working with slices, I can’t guarantee that I can increase the size of the array and/or the strings, since the new memory needs to be adjacent to the one previously allocated.

The solution I came up with was creating a new null-terminated array, and adding a null-terminated copy of each string:

```zig
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();

const dynamic_string_list = try generateStrings(allocator);
defer {
    // Do I need to free each string individually?
    for (dynamic_string_list) |str| {
        allocator.free(str);
    }
    allocator.free(dynamic_string_list);
}

const c_compatible_string_list = try allocator.allocSentinel(
    ?[*:0]u8,
    dynamic_string_list.len,
    null,
);
defer allocator.free(c_compatible_string_list);
for (0..c_compatible_string_list.len) |i| {
    c_compatible_string_list[i] = try allocator.dupeZ(u8, dynamic_string_list[i]);
}
defer {
    for (c_compatible_string_list, dynamic_string_list) |c_str, d_str| {
        allocator.free(c_str.?[0 .. d_str.len + 1]);
    }
    allocator.free(c_compatible_string_list);
}
// I can call the C function like this:
std.debug.print("Dynamic strings:\n", .{});
c.printStringList(@ptrCast(c_compatible_string_list));

```

Is there a better way to do this?

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [March 6, 2025, 11:43am UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/8 "2025-03-06T11:43:07Z")

</div>

Nope.  
I personally would rewrite the function to return the type you need to avoid the double allocation, but it shouldn’t matter much

you don’t need the `@ptrCast`, it should coerce

---

<div class="post-metadata">

**Author:** ![videbar](https://ziggit.dev/letter_avatar_proxy/v4/letter/v/e480ec/32.png) [@videbar](https://ziggit.dev/u/videbar)\
**Post date:** [March 6, 2025, 1:13pm UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/9 "2025-03-06T13:13:34Z")

</div>

I see, thanks. Also, without using `@ptrCast()` I get an error:

```zig
error: expected type '[*c]const [*c]const u8', found '[:null]?[*:0]u8'
    c.printStringList(c_compatible_string_list);
                      ^ ~~~~~~~~~~~~~~~~~~~~~~~

```

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [March 6, 2025, 1:43pm UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/10 "2025-03-06T13:43:14Z")

</div>

> [@videbar](#):
>
> `c.printStringList(c_compatible_string_list);`

```zig
c.printStringList(c_compatible_string_list.ptr);

```

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [March 7, 2025, 5:39am UTC](https://ziggit.dev/t/casting-to-a-c-array-of-strings/8872/11 "2025-03-07T05:39:57Z")

</div>

Oops, I was thinking `[*]` not `[*c]` for coercion
