# Convert Vector{String} to Ptr{Ptr{UInt8}}?

**URL:** <https://discourse.julialang.org/t/convert-vector-string-to-ptr-ptr-uint8/102793>\
**Category:** New to Julia\
**Tags:** c\
**Created:** [August 14, 2023, 4:00pm UTC](https://discourse.julialang.org/t/convert-vector-string-to-ptr-ptr-uint8/102793 "2023-08-14T16:00:05Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![frylock](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frylock/32/50213_2.png) [@frylock](https://discourse.julialang.org/u/frylock)\
**Post date:** [August 14, 2023, 4:00pm UTC](https://discourse.julialang.org/t/convert-vector-string-to-ptr-ptr-uint8/102793/1 "2023-08-14T16:00:05Z")

</div>

I’m aware that Julia strings are unicode things, but if I make sure that the strings are ASCII clean, I can figure out how to convert Vector{String} → Vector{Vector{UInt8}}, but not to Ptr{Ptr{UInt8}} …

```julia
In [1]: a = ["hi", "there"]
In [2]: b = map(x -> Vector{UInt8}(x), a)
In [3]: typeof(b)
Out[3]: Vector{Vector{UInt8}} (alias for Array{Array{UInt8, 1}, 1})

```

The function that I am trying to call:

```sh
frylock@laptop:~/Projects/Julia_C/$ nm -D --defined-only --demangle libstuff.so
0000000000001139 T stuff(char**)

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [August 14, 2023, 4:17pm UTC](https://discourse.julialang.org/t/convert-vector-string-to-ptr-ptr-uint8/102793/2 "2023-08-14T16:17:40Z")

</div>

The signature alone is not enough, you have to know whether C expects an array of pointers, or a pointer to an array of chars (which in C are both `char**`). You will have to create a new array; you cannot cleanly convert a `Vector{Vector{String}}` to a `char**`, because the representations of the two aren’t a 1:1 mapping (not even on the bit level).

---

<div class="post-metadata">

**Author:** ![frylock](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frylock/32/50213_2.png) [@frylock](https://discourse.julialang.org/u/frylock)\
**Post date:** [August 14, 2023, 4:21pm UTC](https://discourse.julialang.org/t/convert-vector-string-to-ptr-ptr-uint8/102793/3 "2023-08-14T16:21:03Z")

</div>

The function with the `stuff(char **)` signature is supposed to be a wrapper for a library function that expects `std::vector<std::string>`. Perhaps I should have mentioned that in case I was proposing an X Y problem.

So the larger issue is that I need to get a list of strings from Julia-land to a C++ function that wants `std::vector<std::string>`.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 14, 2023, 5:09pm UTC](https://discourse.julialang.org/t/convert-vector-string-to-ptr-ptr-uint8/102793/4 "2023-08-14T17:09:28Z")

</div>

> [@frylock](#):
>
> `stuff(char**)`

Probably you want something like:

```julia
function stuff(strings::AbstractVector{String})
    GC.@preserve strings begin
        ptrs = Cstring[Base.unsafe_convert(Cstring, s) for s in strings] # array of pointers to char
        @ccall stuff(ptrs::Ptr{Cstring})::Cvoid # or whatever your type signature is
    end
end

```

So that you allocate an array of `Cstring` (equivalent to an array of `char*`, and ensured to be NUL-terminated for C string compatibility) to pass to your C function (`Ptr{Cstring}` acts like `char**`). `GC.@preserve` is used to ensure that the `strings` array is not garbage collected (is “rooted”) while the `ccall` executes.

> [@frylock](#):
>
> if I make sure that the strings are ASCII clean

This is usually not a concern. Unicode can still be passed as a `char*` (e.g. as data for `std::string`), it is just UTF-8 encoded. To the extent that your application actually cares about the contents of the strings (as opposed to just treating strings as atoms, e.g. filenames), of course, it may need to be UTF8-aware (but not always, e.g. if it is just looking for ASCII substrings).

> [@frylock](#):
>
> So the larger issue is that I need to get a list of strings from Julia-land to a C++ function that wants `std::vector<std::string>`.

You usually need some kind of C wrapper for this, either written manually or ala [CxxWrap.jl](https://github.com/JuliaInterop/CxxWrap.jl).

---

<div class="post-metadata">

**Author:** ![frylock](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frylock/32/50213_2.png) [@frylock](https://discourse.julialang.org/u/frylock)\
**Post date:** [August 14, 2023, 5:54pm UTC](https://discourse.julialang.org/t/convert-vector-string-to-ptr-ptr-uint8/102793/5 "2023-08-14T17:54:23Z")

</div>

And in case this is useful for someone in the future:

> **My test C++ code**
>
> ```cpp
> #include <iostream>
> #include <vector>
> 
> typedef struct {
> size_t size;
> char **data;
> } _StringList;
> 
> #ifdef __cplusplus
> extern "C" {
> #endif
> 
> void stuff(_StringList sl) {
> for (size_t i = 0; i < sl.size; ++i)
> std::cout << sl.data[i] << std::endl;
> }
> 
> #ifdef __cplusplus
> } // extern "C"
> #endif
> 
> ```

EDIT: applied @stevengj 's suggested edit.

> **My test Julia script**
>
> ```julia
> struct StringList
> size::Csize_t
> data::Ptr{Cstring}
> end
> 
> a = ["hi", "there"]
> 
> GC.@preserve a begin
> t1 = Cstring[Base.unsafe_convert(Cstring, s) for s in a]
> GC.@preserve a begin
> t2 = Base.unsafe_convert(Ptr{Cstring}, t1)
> s = StringList(length(a), t2)
> @show @ccall "./libstuff.so".stuff(s::StringList)::Cvoid
> end
> end
> 
> ```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 14, 2023, 6:09pm UTC](https://discourse.julialang.org/t/convert-vector-string-to-ptr-ptr-uint8/102793/6 "2023-08-14T18:09:29Z")

</div>

> [@frylock](#):
>
> ```julia
> GC.@preserve a begin
> t1 = Cstring[Base.unsafe_convert(Cstring, s) for s in a]
> t2 = Base.unsafe_convert(Ptr{Cstring}, t1)
> s = StringList(length(a), t2)
> @show @ccall "./libstuff.so".stuff(s::StringList)::Cvoid
> end
> 
> ```

This is unsafe since `t1` could get garbage collected before you are done with it. You need something like:

```julia
GC.@preserve a begin
    t1 = Cstring[Base.unsafe_convert(Cstring, s) for s in a]
    GC.@preserve t1 begin
        s = StringList(length(a), pointer(t1))
        @show @ccall "./libstuff.so".stuff(s::StringList)::Cvoid
    end
end

```
