C/C++ Arena

Step 8 of 8

Challenge: a CSV report

This challenge is a realistic batch job: read a data file, aggregate it, write a report file. It combines files, strings, arrays of structs and parsing.

CSV

A CSV (comma-separated values) file stores a table as text: one row per line, fields separated by commas, often with a header line naming the columns. Spreadsheets and databases export it everywhere.

Parsing a line with sscanf

sscanf is scanf reading from a string instead of input, perfect for parsing a line you already read with fgets. The format %15[^,] is a scan set: it reads up to 15 characters that are not commas, which is how you grab a text field that ends at a comma.

#include <stdio.h>

int main(void) {
    const char *rows[] = {"apples,12", "pears,7", "bad row"};
    for (int i = 0; i < 3; i++) {
        char name[16];
        int count;
        if (sscanf(rows[i], "%15[^,],%d", name, &count) == 2) {
            printf("%s -> %d\n", name, count);
        } else {
            printf("skipped: %s\n", rows[i]);
        }
    }
    return 0;
}
apples -> 12
pears -> 7
skipped: bad row

Aggregating by key

To total amounts per region, keep an array of {name, total} structs and a count. For each row, search the array for the region with strcmp; if it's there, add to its total; if not, append a new entry. Appending new keys at the end keeps them in the order they first appeared.

Plan it

  1. Open the input; skip the header with one fgets.
  2. For each line: parse, find or add the region, add the amount.
  3. Open report.txt for writing, write one line per region, close it.
  4. Reopen it for reading and print each line.

Check every fopen, and close every file.

Your turn:

sales.csv starts with a header line, then region,amount rows (amounts are whole dollars).

  1. Skip the header, then total the amounts per region (at most 10 regions, names up to 15 characters), keeping regions in the order they first appear.
  2. Write report.txt with one REGION TOTAL line per region.
  3. Then read report.txt back and print it, so the test can see what you wrote.

Tip: sscanf(line, "%15[^,],%d", region, &amount) reads everything up to the comma as the region, then the number.

Previous: Binary files