how Rust maps onto the C concepts
If you have learned C, you have not wasted your time — you have built exactly the mental model Rust assumes. Rust is a systems language built on the same machine, so the hardware-level concepts you now carry transfer almost one-for-one; what changes is who is responsible for getting the details right. It helps to lay the pieces side by side so the new language feels less like a foreign country and more like the same city with better road signs.
Walk the map. The stack and the heap are the same two regions of process memory in both languages: local variables and small values live on the stack and are cleaned up when a function returns; larger or longer-lived data lives on the heap. In C you put data on the heap with malloc and take it back with free; in Rust an owning type like Box<T>, String, or Vec<T> allocates on the heap for you and releases it automatically. A C pointer becomes a Rust reference: &T is a shared, read-only reference, &mut T is an exclusive, writable one, and unlike a raw pointer the compiler guarantees a reference always points at valid memory. The manual free becomes an automatic drop that runs at the end of the owner's scope, so you never call free yourself. Where C uses a possibly-NULL pointer to mean maybe-nothing, Rust uses Option<T>; where C returns -1 and sets errno, Rust returns Result<T, E>; where C describes data as a pointer plus a length you track by hand, Rust uses a slice that carries the length with it.
Why this framing helps: it tells you precisely what is new and what is not. The hardware reality — bytes, addresses, the stack growing down, the heap, the cost of a cache miss — is identical, so all your low-level intuition is still good. What Rust adds is a compiler that tracks ownership, borrowing, and lifetimes so that the bookkeeping you did by hand and comment in C is now checked for you. The honest caveat is that the mapping is a guide, not an equation: Box<T> is not literally malloc, a reference is not literally a C pointer (it carries rules a pointer does not), and Rust's drop order and move semantics have details with no C equivalent. Use the map to get oriented, then learn the places where Rust genuinely differs.
// C Rust // malloc / free Box<T> / automatic drop // char *p (may be NULL) Option<&T> / &T (never null) // returns -1, sets errno returns Result<T, E> // ptr + length you track &[T] (a slice carries its length) // you call free() drop runs at end of owner's scope
Same hardware, same regions; Rust moves the bookkeeping from your head into the compiler.
The map orients you but is not exact: a Rust reference is not just a C pointer (it carries borrowing rules), and Box<T> is not literally malloc. Your low-level hardware intuition transfers; the details of moves, drop order, and lifetimes are genuinely new.