Activity 24 - Stack and Heap Diagram Practice
Instructions
For each code snippet below:
- Draw the stack and heap at the moment indicated by the comment
// DRAW HERE - Draw from the bottom up! With the stack on the left, heap on the right
- Label each variable on the with its type and metadata (len, cap)
- Show what's stored on the heap (if anything)
- Draw arrows for references (regular
&and mutable&mut) - For fat pointers (slices), show both the pointer and the metadata (len)
- For multiple stack frames, box each stack frame and label its scope.
- Remember to allocate space for a return values and other variables in a frame before adding the next frame!
Tips
- Start with the stack: Draw all local variables in the current frame
- Add heap data: For Box, String, Vec, draw boxes on the heap
- Draw arrows: References are just pointers - draw arrows from stack to stack or stack to heap
- Fat pointers: Remember slices store ptr + len
- Multiple frames: Stack them vertically, with newer frames at the top
- Trace execution: Follow the code line by line to see how values change
Common Mistakes to Avoid
- Drawing references as pointing directly to heap (they usually point to stack variables!)
- Forgetting that slices are fat pointers (ptr + length)
- Not showing the metadata (capacity, length) for String and Vec
- Forgetting that values can change during execution (trace carefully!)
- Forgetting to allocate space for a return value / all variables in a stack frame before adding a new frame
Problem 1
Concepts: Primitives on stack, Box, String, Vec on heap
fn main() { let x = 42; let y = Box::new(100); let s = String::from("hello"); let v = vec![1, 2, 3]; // DRAW HERE }
Problem 2
Concepts: Immutable references, mutable references
fn main() { let mut x = 10; let y = 20; let r1 = &y; let r2 = &mut x; *r2 = 15; // DRAW HERE }
Problem 3: Your turn
Concepts: References to Box, String, and Vec
fn main() { let mut numbers = vec![10, 20, 30]; let name = String::from("Alice"); let boxed = Box::new(42); let r1 = &numbers; let r2 = &mut numbers; let r3 = &name; let r4 = &boxed; r2.push(40); // DRAW HERE }
Problem 4:
Concepts: Slices as fat pointers with ptr + length
fn main() { let data = vec![5, 10, 15, 20, 25]; let slice = &data[1..4]; // DRAW HERE }
Problem 5:
Concepts: Multiple stack frames, passing references across frames
fn process(x: &mut i32, y: &i32) { *x = x + y; // DRAW HERE } fn main() { let mut a = 10; let b = 5; process(&mut a, &b); }
Problem 6:
Concepts: Multiple frames, heap data, references, slices
fn analyze(numbers: &Vec<i32>, window: &[i32]) -> i32 { let first = window[0]; let sum_ref = &first; // DRAW HERE first + numbers.len() as i32 } fn main() { let mut data = vec![100, 200, 300, 400]; let slice = &data[1..3]; let result = analyze(&data, slice); }
Problem 7: Mutable references across frames
Concepts: Mutable references, multiple frames, heap mutations
fn append_data(list: &mut Vec<i32>, value: i32) { list.push(value); let last = &list[list.len() - 1]; // DRAW HERE } fn main() { let mut numbers = vec![10, 20]; append_data(&mut numbers, 30); }