A pointer holds a memory address. Dereferencing accesses the value at that address. In Rust, `*pointer` performs the operation: it can read a value, or write one when the pointer permits it. section 3.1.1 section 3.2.2
A raw pointer and a Rust reference both hold an address, but the compiler treats them differently. References carry information, including lifetimes, that lets the compiler enforce their validity. Raw pointers lack those guarantees, so dereferencing one requires an `unsafe` block. That block does not validate the address; the programmer must do so. section 3.1.1
Read a buffer through a raw pointer
Given `data: Vec<u8>` containing `5, 10, 15, 20`, pass `data.as_ptr()` and `data.len()` to a reader. For each index, `*slice_p.offset(index as isize)` reads the corresponding byte inside an `unsafe` block. The pointer identifies where the buffer starts; the length controls how many elements the loop attempts to read. section 3.1.1
Listing 3.1 Reading the elements of a vector using pointer arithmetic
fn main() {
let data: Vec<u8> = vec![5, 10, 15, 20]; #1
read_u8_slice(data.as_ptr(), data.len()); #2
}
fn read_u8_slice(slice_p: *const u8, length: usize) { #3
for index in 0..length {
unsafe { #4
println!("slice[{}] = {}", index,
*slice_p.offset(index as isize)); #5
}
}
}
Shows the complete vector-reading loop, including the pointer, length, offset, and `unsafe` dereference. section 3.1.1
Write a result back to C
A C caller passes `&solution` to a Rust `solve` function as a `*mut c_int` out parameter. A no-op `solve` leaves the displayed result unpredictable. First check `solution.is_null()` and return an error if it is null; then `unsafe { *solution = 1024; }` writes a test value for the caller to print. This verifies the write across the language boundary before implementing the calculation. A null check matters because dereferencing null is undefined behavior; it is not, by itself, a guarantee that every other pointer is valid. section 3.2.2 section 3.1.1
#[no_mangle]
pub extern "C" fn solve(
line: *const c_char, solution: *mut c_int) -> c_int {
if solution.is_null() { #1
return 1;
}
unsafe {
*solution = 1024; #2
}
0
}
Shows the C-compatible `solve` function with its null check and isolated pointer write. section 3.2.2
Input pointers need care too. Before reading a C string passed as `*const c_char`, check for null, use `CStr::from_ptr` in an `unsafe` block, and handle conversion to a Rust string. That lets Rust read the C-owned string without allocating a second copy. section 3.2.2


