CodeBlanks Logo Icon CodeBlanks

CString and CStr

Convert C strings with CString and CStr.

CString and CStr

C strings are byte arrays ending with a null byte (\0); Rust strings know their length and may contain \0. The bridge is two types:

  • CString: an owned string ending with \0; for sending from Rust to C.
  • CStr: a borrowed C string; for reading a pointer coming from C.
use std::ffi::{CStr, CString};

let c = CString::new("merhaba").unwrap();
let n = unsafe { strlen(c.as_ptr()) };      // 7

let s = CStr::from_bytes_with_nul(b"rust\0").unwrap();
println!("{}", s.to_str().unwrap());        // rust

A common mistake: a dangling pointer

The pointer from as_ptr is only valid as long as the CString lives. Taking a pointer from a temporary produces a dangling pointer:

// WRONG: the CString is dropped immediately, p is left invalid
let p = CString::new("x").unwrap().as_ptr();

// RIGHT: bind it to a variable first
let c = CString::new("x").unwrap();
let p = c.as_ptr();   // valid as long as c lives

To hand ownership to C, use into_raw; to take it back, CString::from_raw.

Practice C strings

Declare C's strlen function. Get the length of CString::new("merhaba") with strlen; convert CStr::from_bytes_with_nul(b"rust\0") to a &str; find the result of CString::new("a\0b").is_err(). Print all three separated by spaces.

Starter code

main.rs
use std::ffi::{c_char, CStr, CString};

fn main() {
    // buraya yaz
}

Sample solution

main.rs
use std::ffi::{c_char, CStr, CString};

unsafe extern "C" {
    fn strlen(s: *const c_char) -> usize;
}

fn main() {
    let c = CString::new("merhaba").unwrap();
    // SAFETY: c geçerli, sonu boş baytla biten bir dizedir.
    let n = unsafe { strlen(c.as_ptr()) };
    let s = CStr::from_bytes_with_nul(b"rust\0").unwrap();
    let hata = CString::new("a\0b").is_err();
    println!("{} {} {}", n, s.to_str().unwrap(), hata);
}

Expected output

7 rust true

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Why does <code>CString::new("a\0b")</code> error?

  • b is invalid
  • It's too short
  • It doesn't error
  • The inner \0 would end the string early on the C side Correct answer

Explanation: If CString::new finds an inner null byte, it returns NulError, preventing silent truncation.

2 Create a C string

Question
let c = ____::new("merhaba").unwrap();
let n = unsafe { strlen(c.as_ptr()) };
Answer
let c = CString::new("merhaba").unwrap();
let n = unsafe { strlen(c.as_ptr()) };

Explanation: CString is for sending strings from Rust to C.

3 Type and direction

Term Meaning
CString Rust → C (owned)
CStr C → Rust (borrowed)
as_ptr() *const c_char
into_raw() Give ownership to C

All lessons in Advanced