file-handling · beginner · ~20 min

Final Project: mini-cat — concatenate buffers

Safe bounded copy with a running pointer + remaining-capacity counter.

Challenge

Concatenate several byte buffers into one fixed-size output, truncating safely so you never overrun — the bounded-copy pattern behind cat.

Task

Implement size_t cat_buffers(const char **bufs, const size_t *lens, size_t n, char *out, size_t cap) that appends bufs[0], bufs[1], ..., bufs[n-1] into out, writing at most cap bytes total including the trailing NUL.

Input

  • bufs: array of n source buffers; lens[i] is the length of bufs[i].
  • n: number of buffers (may be 0).
  • out / cap: destination buffer and its capacity (cap >= 1).

Output

Return the number of bytes written, not counting the trailing NUL. out is always NUL-terminated. If the inputs would exceed cap, copy as much as fits and stop (safe truncation).

Example

bufs={"hello, ","world","!"}, lens={7,5,1}, cap=32   ->   13, out="hello, world!"
same inputs, cap=6                                   ->   5,  out="hello"
same inputs, cap=1                                   ->   0,  out=""
n=0, cap=8                                            ->   0,  out=""

Edge cases

  • cap == 1: only the NUL fits, so 0 bytes are written.
  • n == 0: just NUL-terminate out, return 0.
  • A single buffer larger than cap: truncate.

Rules

  • No malloc. Reserve one byte for the NUL before copying.

Why this matters

cat looks trivial but the careful concatenation with bounds checking is a model for all 'copy bytes into a fixed buffer' patterns — the place where strncpy footguns kill projects.

Input format

bufs[n] sources with lengths lens[n]; out/cap destination (cap >= 1).

Output format

Bytes written excluding the NUL; out is always NUL-terminated.

Constraints

No malloc; truncate to fit cap, reserving a byte for the NUL.

Starter code

#include <stddef.h>
size_t cat_buffers(const char **bufs, const size_t *lens, size_t n, char *out, size_t cap) { /* TODO */ return 0; }

Common mistakes

Forgetting the NUL byte in the budget; using strcat (re-scans every call — O(n^2)); writing one byte past the buffer.

Edge cases to handle

cap == 1 (only the NUL fits). n == 0 (just NUL out). One buffer larger than cap (truncate).

Complexity

O(total bytes).

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.