str::as_ptr¶
Level: reference · for working programmers
One line: The raw address of the first byte, as *const u8 — for handing text to C, and for nothing else in ordinary code.
Stable since 1.0.0. Usable in a const context.
A &str is a pointer and a length; as_ptr is the pointer half. Reading through it is unsafe, and two invariants come with it.
It is not NUL-terminated. A Rust string knows its length, so it does not need a terminator and does not have one. Passing s.as_ptr() to a C function expecting char * reads past the end of the string. Use CString when a C API wants a terminated string.
The pointer is only valid while the string is. Keeping it past the owner's drop, or past a push_str that reallocates, leaves it dangling — and nothing warns you, because a raw pointer is not tracked by the borrow checker.
In safe code the honest uses are narrow: FFI, and identity checks like "is this slice a view into that buffer". For the second, substr_range answers the same question without raw pointers.
Example¶
str_as_ptr.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
fn main() {
let s = "hello";
// Addresses differ every run, so prove the layout with *derived* arithmetic.
let start = s.as_ptr() as usize;
let third = s[2..].as_ptr() as usize;
println!("a slice at byte 2 starts {} bytes along", third - start);
// The pointer plus the length is the whole of a &str.
let rebuilt = unsafe { std::slice::from_raw_parts(s.as_ptr(), s.len()) };
println!("{:?}", std::str::from_utf8(rebuilt));
// No terminator: the length is carried beside the pointer, not in the
// bytes, which is why a C API needs CString rather than this pointer.
println!("len is carried separately: {}", s.len());
// Growing past the capacity gets a new buffer, so any pointer taken
// before it is stale. Capacity is the deterministic signal; whether the
// address itself changes is up to the allocator.
let mut owned = String::with_capacity(4);
owned.push_str("abcd");
let before = owned.capacity();
owned.push_str("efgh");
println!("capacity {} -> {}", before, owned.capacity());
}
Verified output of str_as_ptr.rs — regenerated by tools/run_examples.py, never hand-typed.
See also¶
str::as_mut_ptr— the mutable counterpartstr::as_bytes— what you almost always want insteadstr::substr_range— answers 'is this a view into that' safely
str::as_ptr in the standard library ↗
Po polsku¶
as_ptr zwraca surowy wskaźnik (raw pointer) *const u8 na pierwszy bajt — czyli tylko połowę tego, czym jest &str, bo druga połowa to długość trzymana obok wskaźnika, a nie w danych. Dla kogoś, kto przychodzi z C, to jest właśnie ta pułapka: tam łańcuch kończy się bajtem zerowym, tutaj żadnego terminatora nie ma, więc s.as_ptr() przekazany funkcji oczekującej char * czyta poza koniec tekstu — do FFI służy CString, nie ten wskaźnik. Druga pułapka jest cichsza: surowego wskaźnika nie pilnuje borrow checker, więc nic nie krzyknie, gdy przeżyje on swój łańcuch albo realokację po push_str — dostajesz zwisający wskaźnik bez jednego ostrzeżenia. W bezpiecznym kodzie prawie zawsze chodziło ci o as_bytes.
Szukaj po polsku: surowy wskaźnik · wskaźnik plus długość · rust str as_ptr · rust CString null terminated FFI · rust raw pointer dangling