|
|
||
|---|---|---|
| .forgejo/workflows | ||
| include | ||
| src | ||
| tests | ||
| .gitignore | ||
| compile_commands.json | ||
| Makefile | ||
| README.md | ||
Record Manager — Instructor Reference Solution (M1–M5)
PRIVATE — never ships to students. This is the reference implementation for
the Record Manager cumulative project (assignments/projects/), milestone by
milestone, plus the graded-interface contract and grading notes.
Layout
include/record.h M1 record_t + record_new/free + status_t
include/buf.h M2 dynamic string buffer (+ readline)
include/list.h M3 opaque list_t + append/find/remove (+ len/get/sort helpers)
include/store.h M4 store_save / store_load (text file, '|' delimiter)
src/record.c M1 deep-copy record lifecycle
src/buf.c M2 growable buffer: append/appendc/cstr/reset/free/readline
src/list.c M3 singly linked list; remove frees node + record
src/store.c M4 one record per line; load appends + reports count
src/main.c M5 menu (add/list/search/delete/save/load/help/quit)
Makefile builds recman + recman_asan; `make test` runs unit + smoke
tests/unit.c direct tests of buf/list/store (links library sources)
tests/smoke.sh end-to-end CLI session
Build + verify
make # recman
make asan # recman_asan (ASan+UBSan)
make test # unit + smoke, both under ASan/UBSan
Reference must be -std=c17 -Wall -Wextra -Wpedantic -Werror clean and report
0 bytes lost under Valgrind.
Graded interface (what hidden tests touch)
record_new, record_free, list_new, list_free, list_append, list_find,
list_remove, store_save, store_load — exact signatures in
assignments/projects/README.md. This reference adds three non-graded helpers
(list_len, list_get, list_sort) that the menu and store layer need; they
are extra, not substitutes.
Contract decisions (documented for graders)
list_remove: returns0on success,STATUS_ERR_NOTFOUNDwhen no record matches,STATUS_ERR_ARGon NULL args. Frees the matching record + node.store_load: returns the number of records read (≥ 0) on success; negativestatus_ton error. "0 on success" from the interface table is satisfied when the file is empty/blank. It appends into the existing list.- Delimiter
|: none of the three flavors' fields (email/phone, assignment/ score, category/amount) can contain|;namemay contain spaces — the delimiter is safe across all flavors. - Empty fields: saved as empty strings; loaded back as empty strings
(never NULL from
store_load).
Milestone-by-milestone notes
M2 — dynamic string buffer (week 7)
Hidden tests likely: appends beyond initial capacity, buf_cstr NUL-termination
after every append, reset-then-reuse, buf_readline on a long line (>256 chars),
EOF/empty-line behavior. Sticky-OOM flag keeps the buffer usable after a failed
realloc. Common mistake: forgetting the +1 for the NUL in buf_grow, or
realloc-ing to a shrinking capacity.
M3 — linked list (week 11)
Hidden tests likely: append to empty list, find across many nodes, remove head /
remove middle / remove missing, list_free of a 3-node list under Valgrind
(0 lost), NULL-arg safety. Common mistakes: freeing the record and then
walking next (order matters — save next first); list_remove freeing the
node but not the record (double-free later); storing record_t * by value
instead of pointer.
M4 — text file save/load (week 13)
Hidden tests likely: save→load round-trip preserves order + all three fields;
load into a non-empty list appends; file with blank lines; missing file returns
error, not crash; fields containing spaces survive (the | delimiter).
Common mistakes: assuming fgets succeeds; writing with fprintf and never
checking ferror; not stripping \n; strtok mangles empty fields (use
strchr splitting instead — empty field1/field2 must survive).
M5 — refactor + search/sort + hardening (week 15)
Hidden tests likely: multi-file build with one make; case-insensitive
substring search across all three fields; sort alphabetical by name;
ASan/UBSan-clean; Valgrind 0 lost. Common mistakes: search matching only
name; sort comparing record_t* pointers instead of ->name; -Werror
violations from unused includes after the refactor.
Grading sanity checks
makefrom a clean tree (no build/ artifacts committed).make asan && ./build/recman_asan→ add 3 records → delete middle → save → quit → reload →listshows the surviving two in order.valgrind --leak-check=full ./build/recmanwith the same session →0 bytes lost(the menu leaks nothing).- Feed the
tests/fixtures: long input line (buf), 10k-record list (list), save/load with spaces and empties (store).