← Back to Rust Course | Chapter 13: Smart Pointers & Unsafe | Lesson 7 of 7

Raw Pointers

Raw pointers are bare-bones addresses in memory that Rust lets you use, but only inside unsafe, since they skip the usual safety checks.
Syntax
rust
let p = &value as *const Type;
let p = &mut value as *mut Type;
unsafe {
    let v = *p;
}

Creating Raw Pointers

Raw pointers can be created from references using as *const T or as *mut T. Creating a raw pointer itself is completely safe -- only dereferencing it requires unsafe.

Example: Creating Raw Pointers

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `value`, set to `100`
    let value = 100;
    // Declare an immutable variable `const_ptr`, set to `&value as *const i32`
    let const_ptr = &value as *const i32;
    // Print "Pointer created (not yet dereferenced)" to the console (with a trailing newline)
    println!("Pointer created (not yet dereferenced)");
    unsafe {
        // Print "Value: {}" to the console, substituting in `*const_ptr` (with a trailing newline)
        println!("Value: {}", *const_ptr);
    }
}

Mutable Raw Pointers

*mut T allows modifying the pointed-to data through the pointer, but like all raw pointer dereferences, doing so requires an unsafe block.

Example: Mutable Raw Pointers

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare a mutable variable `value`, initialized to `5`
    let mut value = 5;
    // Declare an immutable variable `mut_ptr`, set to `&mut value as *mut i32`
    let mut_ptr = &mut value as *mut i32;
    unsafe {
        *mut_ptr += 1;
    }
    // Print "value = {}" to the console, substituting in `value` (with a trailing newline)
    println!("value = {}", value);
}

Raw Pointers Skip Borrow Checking

Unlike references, you can have multiple raw pointers (even mutable ones) to the same data at once, since the borrow checker does not track raw pointers -- this is exactly why dereferencing them is unsafe.

Example: Raw Pointers Skip Borrow Checking

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare a mutable variable `number`, initialized to `10`
    let mut number = 10;
    // Declare an immutable variable `p1`, set to `&mut number as *mut i32`
    let p1 = &mut number as *mut i32;
    // Declare an immutable variable `p2`, set to `&mut number as *mut i32`
    let p2 = &mut number as *mut i32;
    unsafe {
        *p1 += 1;
        *p2 += 1;
    }
    // Print "number = {}" to the console, substituting in `number` (with a trailing newline)
    println!("number = {}", number);
}

Why Raw Pointers Exist

Raw pointers are essential for low-level tasks like foreign function interfaces (calling C code) and for building safe abstractions internally, where the implementer manually guarantees the safety invariants the compiler cannot check.

Example: Why Raw Pointers Exist

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `array`, set to `[1, 2, 3, 4]`
    let array = [1, 2, 3, 4];
    // Declare an immutable variable `ptr`, set to `array.as_ptr()`
    let ptr = array.as_ptr();
    unsafe {
        // Print "First element via raw pointer: {}" to the console, substituting in `*ptr` (with a trailing newline)
        println!("First element via raw pointer: {}", *ptr);
        // Print "Second element via offset: {}" to the console, substituting in `*ptr.offset(1)` (with a trailing newline)
        println!("Second element via offset: {}", *ptr.offset(1));
    }
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Dereferencing a raw pointer outside of an unsafe block, which is a compile error.
  2. Creating a raw pointer to data that has already gone out of scope, resulting in a dangling pointer that is legal to create but unsafe to dereference.
  3. Confusing *const T (immutable raw pointer) with *mut T (mutable raw pointer) -- they have different capabilities.
Chapter Summary
  • *const T and *mut T are raw pointers that bypass Rust's normal borrowing rules.
  • Creating a raw pointer is safe; dereferencing one requires an unsafe block.
  • Raw pointers can be null, dangling, or unaligned -- Rust does not guarantee their validity the way it does for references.
  • Raw pointers are mainly used for low-level interoperability (like FFI) and building custom safe abstractions.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.