Rust Raw Pointers
A raw pointer is a pointer the compiler does not watch. Raw pointers help build safe tools and talk to C.
Create one in safe code
Creating a raw pointer harms nothing, so it needs no unsafe block. The * in *const and *mut is part of the type name, not a dereference:
let mut num = 5;
let r1 = &raw const num; // r1: *const i32
let r2 = &raw mut num; // r2: *mut i32Read and write through it (unsafe)
Only the dereference needs the block:
println!("read = {}", unsafe { *r1 });
unsafe { *r2 = 10; }
println!("now = {}", unsafe { *r2 });The borrow rules do not apply
Two *mut pointers may point at the same value at the same time โ references would never allow this:
let mut score = 1;
let a = &raw mut score;
let b = &raw mut score;
unsafe { *a += 1; *b += 1; }
println!("score = {score}");A pointer from a chosen address
A cast turns any number into a pointer to an address you chose. Making it is allowed โ but it points nowhere you own, so never read through it:
let address = 0x012345usize;
let ptr = address as *const i32;Rebuild a slice from parts
slice::from_raw_parts takes a pointer and a length from a live slice. It rebuilds the slice. This is the pattern behind buffers shared with C. It is also behind safe wrappers like split_at_mut in the next lesson:
let values = [3, 1, 4];
let rebuilt = unsafe { std::slice::from_raw_parts(values.as_ptr(), values.len()) };
println!("rebuilt = {:?}", rebuilt);A pointer that promises nothing
A raw pointer may even be null โ this one is, on purpose. Nothing checks a raw pointer and nothing cleans it up:
let nothing: *const i32 = std::ptr::null();
println!("is null = {}", nothing.is_null());Example
fn main() {
let mut num = 5;
let r1 = &raw const num;
let r2 = &raw mut num;
unsafe {
println!("r1 = {}", *r1);
*r2 = 10;
println!("r2 = {}", *r2);
}
}Key points
- A raw pointer may be null, dangling, or unaligned.
- Nothing cleans it up.
- You must be sure it is valid.
- References promise validity.
- Raw pointers promise nothing.
- Use raw pointers to build safe tools that the borrow checker cannot understand.
In this example, num starts at 5. r1 is a *const i32 made with &raw const. r2 is a *mut i32 made with &raw mut. Both point at num at the same time. References would forbid that. Inside unsafe, *r1 reads 5. Then *r2 = 10 writes through the mutable pointer, and *r2 reads the new value back: r2 = 10.
Note
That loss of promise is exactly the power โ and exactly the danger.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Rust Playground
Exercise
Which part needs an unsafe block?