# How to pass a reference to a vector to C

**URL:** <https://discourse.julialang.org/t/how-to-pass-a-reference-to-a-vector-to-c/136320>\
**Category:** General Usage\
**Tags:** ccall\
**Created:** [March 21, 2026, 1:02pm UTC](https://discourse.julialang.org/t/how-to-pass-a-reference-to-a-vector-to-c/136320 "2026-03-21T13:02:28Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![AwesomeQuest](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/awesomequest/32/38910_2.png) [@AwesomeQuest](https://discourse.julialang.org/u/AwesomeQuest)\
**Post date:** [March 21, 2026, 1:02pm UTC](https://discourse.julialang.org/t/how-to-pass-a-reference-to-a-vector-to-c/136320/1 "2026-03-21T13:02:28Z")

</div>

I’m calling SimpleBLE which has an API where both the reading and writing functions take `(uint8_t** data, size_t* data_length)` that are used to return data in the read case and pass data in the write case.

My confusion lies in how one properly prepares a reference to a Julia vector to be passed to C.

How do I prepare, for instance, a string to be passed as the data in the write case? Since `RefValue{Vector{UInt8}}` can’t convert to `Ptr{Ptr{UInt8}}`

```julia-auto
MethodError: no method matching unsafe_convert(::Type{Ptr{Ptr{UInt8}}}, ::Base.RefValue{Vector{UInt8}})

```

Would it be (this seems to run at least)

```julia-auto
s = "adsf" |> codeunits |> Vector{UInt8}
data_length= Ref(length(s))
data = Ref(pointer(s))

```

In the read case I assume I would just need to

```julia-auto
unsafe_wrap(Vector{UInt8}, data[], data_length[])

```

---

<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:** [March 21, 2026, 2:09pm UTC](https://discourse.julialang.org/t/how-to-pass-a-reference-to-a-vector-to-c/136320/2 "2026-03-21T14:09:14Z")

</div>

> [@AwesomeQuest](#):
>
> I’m calling SimpleBLE which has an API where both the reading and writing functions take `(uint8_t** data, size_t* data_length)` that are used to return data in the read case and pass data in the write case.
> 
> My confusion lies in how one properly prepares a reference to a Julia vector to be passed to C.

Usually in an API like that the C function will be allocating the array, so you shouldn’t be passing a reference to an existing Julia vector. Instead, you would do something like:

```julia-auto
data_ptr = Ref{Ptr{UInt8}}()
data_length = Ref{Csize_t}()
@ccall somelibrary.somefunction(data_ptr::Ref{Ptr{UInt8}}, data_length::Ref{Csize_t})::Cvoid # if it returns void
data = unsafe_wrap(Array, data_ptr[], data_length[], owns=true)

```

where passing `owns=true` assumes that Julia is supposed to call `free` on the resulting array when it is done with it (otherwise you could make a copy, as in your other thread: [Does `String(unsafe_wrap(cstring, len, own=true))` free the memory it points to?](https://discourse.julialang.org/t/does-string-unsafe-wrap-cstring-len-own-true-free-the-memory-it-points-to/136315))

---

<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:** [March 21, 2026, 2:18pm UTC](https://discourse.julialang.org/t/how-to-pass-a-reference-to-a-vector-to-c/136320/3 "2026-03-21T14:18:33Z")

</div>

> [@AwesomeQuest](#):
>
> ```julia-auto
> s = "adsf" |> codeunits |> Vector{UInt8}
> data_length= Ref(length(s))
> data = Ref(pointer(s))
> 
> ```

This “sort of works” if the C API wants an existing array but:

- you don’t need to convert to a `Vector{UInt8}`, the `codeunits` already gives you a vector-like view, and you can just call `pointer(s)` directly anyway to get a pointer to the bytes of a string
- `length(s)` is wrong — you want `sizeof(s)`, which is the number of bytes. `length(s)` returns the number of Unicode characters, which is generally ≥ the number of bytes because non-ASCII characters require multiple bytes
- the pointer is not rooted so you need to call `GC.@preserve` on the Julia array (or the string `s` if you just use a `codeunits` view or `pointer(s)`) for the `@ccall`, to make sure that the array isn’t garbage-collected during the C call
- I’m suspicious that the C API wants a `uint8_t**` — is it planning to modify the pointer in any way, e.g. by calling `realloc` or `free`? If so you can’t pass a pointer to a Julia array

Assuming that the C API wants a `uint8_t**` to an existing array and doesn’t plan to modify the pointer (which makes no sense as an API but whatever), you could just do:

```julia-auto
s = "some string"
GC.@preserve s @ccall(somelibrary.somefunction(pointer(s)::Ref{Ptr{UInt8}}, sizeof(s)::Ref{Csize_t})::Cvoid) # assuming it returns void

```

and it will create the `Ref` wrappers for you.
