data-structures · intermediate · ~25 min

Final Project: CSV row parser (no quoting)

In-place tokenization without allocation; pointer-into-buffer arithmetic.

Challenge

Split one CSV row into its comma-separated fields, in place.

Task

Implement int csv_parse_row(char *row, char **fields, int max_fields). Split row on commas in place — overwrite each , with '\0' — and store a pointer to the start of each field in fields[]. Return the number of fields found. There is no quoting; commas always separate fields.

Task details

Strip a trailing '\n' (or '\r\n') from row before splitting. Stop adding fields once max_fields pointers have been stored.

Input

  • row: a writable, NUL-terminated buffer holding one CSV row (may end in a newline).
  • fields: an array of at least max_fields char * slots to fill.
  • max_fields: the maximum number of field pointers to store.

Output

int: the number of fields written into fields. Each fields[i] points into row. Non-empty input always yields at least 1 field.

Example

"a,b,c"      ->   3 fields: "a", "b", "c"
"single"     ->   1 field:  "single"
"a,,b\n"    ->   3 fields: "a", "", "b"   (newline stripped)
"trailing,"  ->   2 fields: "trailing", "" (empty trailing field)

Edge cases

  • An empty row yields 1 field that is the empty string.
  • A trailing comma produces an empty final field.

Rules

  • Do not allocate; split in place by mutating row. fields[i] must point into the row buffer.

Why this matters

CSV is the eternal interchange format. A simple, non-quoting parser is enough for >80% of real CSV files and is a great exercise in stateless splitting.

Input format

row: writable NUL-terminated buffer (may end in newline); fields: array of >= max_fields char *; max_fields: pointer-slot count.

Output format

int: number of fields; each fields[i] points into row.

Constraints

No malloc. Modifies row in place.

Starter code

int csv_parse_row(char *row, char **fields, int max_fields) { /* TODO */ return 0; }

Common mistakes

Allocating strdup'd copies (the API contract says split in place); not stripping trailing newline; off-by-one in max_fields.

Edge cases to handle

Empty row returns 1 with fields[0] = empty string. Trailing comma yields an empty last field.

Complexity

O(row length).

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