pointers-memory · intermediate · ~12 min
Encode all the memory-safety rules as a small state machine.
Validate that a resource's lifecycle is well-formed: you may only use or free something that is currently allocated, you may not double-free, and you may not allocate over a resource that is already live.
Implement int valid_lifecycle(const char *ops) over a trace using 'a' (allocate), 'f' (free), 'u' (use). Return 1 if every operation respects its precondition, else 0. No main — the grader calls it.
'a' is valid only when the resource is not currently allocated-and-live (after a free, re-allocation is allowed).'f' is valid only when the resource is currently live (no free-before-alloc, no double-free).'u' is valid only when the resource is currently live (no use-before-alloc, no use-after-free).ops — a NUL-terminated string of 'a', 'f', 'u' characters (may be empty).
Returns 1 if the whole sequence is valid, else 0.
valid_lifecycle("auf") -> 1
valid_lifecycle("afaf") -> 1 (allocate again after freeing)
valid_lifecycle("ufa") -> 0 (use before allocate)
valid_lifecycle("aff") -> 0 (double free)
valid_lifecycle("afu") -> 0 (use after free)
Drill: practice one contract before combining it with other skills.
ops — a NUL-terminated string of 'a', 'f', 'u' characters (may be empty).
Returns 1 if the whole sequence is valid, else 0.
ops is a non-NULL terminated trace. Only a, f, and u are valid. Allocation while live, use/free while not live, or another character returns 0. End-of-trace cleanup is not required by this lifecycle validator.
int valid_lifecycle(const char *ops) {
/* TODO */
return 0;
}
Confusing lifecycle validity with leak freedom, or allowing allocation over a live resource.
Empty trace; double-free; use before allocation; reallocation after free; unknown character; a live resource at the end is allowed.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.