'How do I get a *mut c_char from a Str?

To be able to use C library, I need to give a *mut c_char parameter to a function. But I don't find a way to have it from a str.

I converted my str to a CString, that's ok, but there's no more way from CString to get a *mut c_char in the nightly build. I found that in 0.12.0 there was a method, but now, what is the process to get that *mut c_char?



Solution 1:[1]

let bytes = String::from_str("Test").into_bytes() + b"\0";
let cchars = bytes.map_in_place(|b| b as c_char);
let name: *mut c_char = cchars.as_mut_ptr();

The basic idea is the same as yours but there is no need to slice the Vec explicitly; also a zero byte is appended to the buffer. See also my comment to the question.

Solution 2:[2]

Five years later and none of these solutions are working (for me, at least).

A slightly modified version of this answer:

let string: &str = "Hello, world!";
let bytes: Vec<u8> = String::from(string).into_bytes();
let mut c_chars: Vec<i8> = bytes.iter().map(| c | *c as i8).collect::<Vec<i8>>();

c_chars.push(0); // null terminator

let ptr: *mut c_char = c_chars.as_mut_ptr();

Solution 3:[3]

Look at this piece of documentation, the fn as_mut_ptr() has been moved to the slice part of the API. So you need a mutable slice of type &mut [c_char]. And AFAIK you cannot get that from a CString, those would be read-only.

Instead you can use a mut Vec<c_char>:

let mut x : Vec<c_char> = ...;
let slice = x.as_mut_slice();
let ptr = slice.as_mut_ptr();

Solution 4:[4]

Now (2022), into_raw() works well for me, for example:

use std::ffi::CString;
use std::os::raw::c_char;
fn main() {    
  let c_string = CString::new("Hello!").expect("CString::new failed");
  let raw: *mut c_char = c_string.into_raw();
}

Check https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_raw for more information.

Solution 5:[5]

Thanks to rodrigo's post, I found a way (very dirty, but it works) to solve my problem. Here is the code :

let mut string = std::string::String::from_str("Test");
let bytes = string.into_bytes();
let mut cchar : Vec<c_char> = bytes.map_in_place(|w| w as c_char);
let slice = cchar.as_mut_slice();
let name: *mut c_char = slice.as_mut_ptr();

A bit complex in my opinion

Solution 6:[6]

If you want to

let mut hello =   b"Hello World\0".to_vec().as_mut_ptr() as *mut i8;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vladimir Matveev
Solution 2 Vadim Hagedorn
Solution 3 Shepmaster
Solution 4
Solution 5
Solution 6