Activity 24 - Stack and Heap Diagram Practice

Instructions

For each code snippet below:

  1. Draw the stack and heap at the moment indicated by the comment // DRAW HERE
  2. Draw from the bottom up! With the stack on the left, heap on the right
  3. Label each variable on the with its type and metadata (len, cap)
  4. Show what's stored on the heap (if anything)
  5. Draw arrows for references (regular & and mutable &mut)
  6. For fat pointers (slices), show both the pointer and the metadata (len)
  7. For multiple stack frames, box each stack frame and label its scope.
  8. Remember to allocate space for a return values and other variables in a frame before adding the next frame!

Tips

  1. Start with the stack: Draw all local variables in the current frame
  2. Add heap data: For Box, String, Vec, draw boxes on the heap
  3. Draw arrows: References are just pointers - draw arrows from stack to stack or stack to heap
  4. Fat pointers: Remember slices store ptr + len
  5. Multiple frames: Stack them vertically, with newer frames at the top
  6. 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);
}