๐ŸŽ“ A1Learner
๐Ÿ”

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 i32

Read 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?