Rust: Bridging C Strings with CStr and CString
CString and CStr are Rust's safe wrappers for C's nul-terminated strings. CString builds a C-compatible string to pass *out* of Rust; CStr interprets one coming *in*. Use them for any FFI calls.
Why it exists
Rust strings (String, &str) and C strings are fundamentally incompatible. Rust strings are length-prefixed, always UTF-8, and can contain null bytes (\0). C strings are nul-terminated, have no defined encoding, and their length must be calculated by scanning. This mismatch requires a safe bridge for Foreign Function Interface (FFI) code to prevent memory errors and data corruption.
The mental model
Think of CString and CStr as diplomatic translators between Rust and C. CString takes a Rust string, validates it for C compatibility (no internal nulls), and packages it for C by adding a final null terminator. CStr takes a raw pointer from C, wraps it in a safe Rust slice, and provides tools to inspect it and convert it back to a Rust string, handling potential encoding errors. CString is for exporting strings to C; CStr is for importing strings from C.
How it works
To pass a string from Rust to C, you create an owned CString from a Rust &str using CString::new(). This returns a Result, which will be an Err if the input contains \0 bytes. The CString manages a buffer that is guaranteed to be nul-terminated. You can then get a raw pointer from it using .as_ptr() to pass to the C function.
To receive a string from C, a C function gives you a *const c_char pointer. You wrap it in a borrowed CStr using the unsafe block CStr::from_ptr(). It's unsafe because Rust cannot guarantee the pointer is valid or properly nul-terminated. Once wrapped, CStr provides safe methods like .to_str(), which attempts to convert the byte slice to a Rust &str and returns a Result because the bytes may not be valid UTF-8.
When to use it
Use these types whenever you pass strings across a C ABI boundary. This is critical when calling C libraries (like OpenSSL or SQLite) from Rust, or when exporting Rust functions to be called by C, Python, Ruby, or other languages that use C bindings.
When not to use it
For purely Rust-to-Rust code, String and &str are always superior. For interacting with the operating system (e.g., file paths, environment variables), prefer OsString and OsStr. They correctly handle platform-specific string encodings which may be neither UTF-8 nor C-style nul-terminated strings.
One canonical example
To call a C function void print_msg(const char msg);, you prepare the string in Rust: let rust_string = "Hello from Rust!"; let c_string = CString::new(rust_string).unwrap(); unsafe { print_msg(c_string.as_ptr()); }. To read a string from a C function const char get_msg();, you would do: let raw_ptr = unsafe { get_msg() }; let c_str = unsafe { CStr::from_ptr(raw_ptr) }; let rust_str = c_str.to_str().expect("C string is not valid UTF-8");.
Interview question
What is the primary reason `CStr::from_ptr()` requires an `unsafe` block in Rust?
- a.The function might attempt to free memory not owned by Rust, causing a double-free error.
- b.The resulting `CStr` might contain invalid UTF-8 characters, which could lead to data corruption.
- c.Rust cannot verify that the provided raw pointer is valid, points to a nul-terminated string, or is properly aligned.Correct
- d.It bypasses Rust's ownership system, making the string susceptible to being dropped prematurely.
Why? this is the answer
The card states that `CStr::from_ptr()` is unsafe because "Rust cannot guarantee the pointer is valid or properly nul-terminated." Option B describes a concern handled by `CStr::to_str()`'s `Result` type, not the unsafety of `from_ptr` itself.
Just read this? Test yourself on what you have been reading.
Read the original → doc.rust-lang.org
- #rust
- #ffi
- #memory-safety
- #interop
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on rust — each one lists the topics its interview covers.
See open roles