Byte-Level Memory Allocator (C, 127-byte Heap)
A compact implicit-list heap simulator with 1-byte headers and footers, splitting, coalescing, Best-Fit or First-Fit allocation, and low-level memory I/O commands.
Overview
This group assignment implements a byte-addressable heap of 127 bytes organized as an implicit free list. Each block carries a 1-byte header and 1-byte footer whose most-significant 7 bits encode the block size (including header and footer) and whose least-significant bit is the allocation flag. The program reads commands from a prompt and supports allocation, freeing with forward and backward coalescing, a block listing view, raw memory writes, and raw memory reads. The behavior matches the assignment brief.
Key Features
-
Exact heap model Heap size 127 bytes. Initial state is one free block with header at address 0 and footer at address 126. No alignment assumptions.
-
Headers and footers Pack size and allocation bit into a single byte, placed just before and after the payload. Your code sets both and zeroes payload bytes on init and on free.
-
Allocation strategies First Fit by default, or Best Fit when launched with the
BestFitargument. Splitting occurs when possible; if the remainder would be smaller than 3 bytes, the whole block is allocated. -
Coalescing On
free, the allocator coalesces with the next free block and the previous free block, then rewrites header and footer as a single larger free block. Payload bytes are reset to zero. -
Interactive commands
-
malloc <size>prints the pointer to the first payload byte -
free <index>frees by payload pointer -
blocklistprintspayloadSize-pointer-statussorted by descending payload size, ties broken by lower address first -
writemem <index> <alnum>writes raw bytes starting at index -
printmem <index> <n>prints decimal bytes separated by hyphens -
quitexits All follow the format and semantics required by the brief.
-
Architecture and Data Representation
- Memory:
unsigned char memory[127]represents the entire heap. A helper sets header, footer, and zeroes payload in a single call. - Block encoding:
header = (size << 1) | allocBitfor allocated,(size << 1) & 0xFEfor free. Footer mirrors header. -
Allocator:
- First Fit scans forward and takes the first sufficiently large free block.
- Best Fit scans all blocks to find the smallest sufficient free block.
- Split rule: if
remainder <= 2, do not split. Otherwise create a second free block with correct header and footer.
- Free path: merges with the next free block if present, then with the previous free block if present, writes zeros across the merged region, and sets a single free header and footer.
- Block list: collects block starts, sorts by size descending and address ascending, then prints
size-pointer-statuslines where size is the payload size. - Raw I/O:
writememcopies alphanumeric bytes intomemorystarting at the index.printmemprintsnbytes in decimal with hyphens. Bounds checks are intentionally lax per the brief.
Example Usage
> malloc 10
1
> malloc 5
13
> blocklist
106-20-free
10-1-allocated
5-13-allocated
> free 1
> blocklist
106-20-free
10-1-free
5-13-allocated
> writemem 1 HELLO
> printmem 1 5
72-69-76-76-79
> quit
How to Build and Run
gcc -std=c11 -O2 -Wall -Wextra -o alloc hw4.c
# Default: First Fit
./alloc
# Best Fit
./alloc BestFit
The program prints > and accepts commands until quit. It compiles on OpenLab with GCC 11 as required.
Notes and Edge Cases
- The allocator treats all pointers as heap addresses from 0 to 126 inclusive.
- Writing outside a payload can intentionally corrupt headers, footers, or neighboring blocks, which mirrors the brief’s “no bounds checking” requirement.
- Block sizes in headers and footers include only payload bytes, while pointer values printed by
mallocandblocklistpoint to the first payload byte.