A memory location, or address, is a number identifying one byte in an address space. Think of it as a page number in a table of contents: it tells a program where to look, not what it will find there. An address by itself does not guarantee that the program may read that byte. section 6.1 section 6.4.2
Rust distinguishes the number from the ways code uses it. A raw pointer such as *const i64 identifies the starting byte of an i64 and carries its type; a reference such as &i64 adds Rust’s usual guarantees. An i64 occupies eight bytes, so retrieving its value requires more than the byte named by its starting address. Reading through a raw pointer is unsafe. section 6.1 section 6.2.1
Listing 6.4 Creating a raw pointer (*const T)
fn main() {
let a: i64 = 42;
let a_ptr = &a as *const i64; #1
println!("a: {} ({:p})", a, a_ptr); #2
}
This small Rust program takes a reference to 42, casts it to a raw pointer, and prints both the value and its address with {:p}. It prints the pointer without dereferencing it. section 6.2.1
The addresses a program sees are virtual addresses, not direct descriptions of RAM. The CPU’s memory management unit translates them to physical addresses using instructions maintained by the operating system. Translation is organized into pages, and a cache called the translation lookaside buffer speeds up recent translations. This is why a variable can appear at a large address without the program using that much physical RAM. section 6.4.3 section 6.4.2
Why not scan every address?
Casting successive numbers to *const u8 and reading them does not safely reveal a process’s memory. Starting at 1 avoids a null pointer but still leads to a segmentation fault when the program reaches memory it cannot access. Printing the addresses of known values is a safer way to inspect where they appear in its address space. section 6.4.2


