DMarlon Studio

Lesson 20 · 20 of 20

Project: inventory manager · C

A small inventory manager in C that combines structs, dynamic memory, a linked list and files, and frees all its memory at the end.

C · Project: inventory manager in DMarlon Studio: the example's code and its output in the terminal

This project brings the course together. Each article is an Item with a name, quantity, price and a next pointer: the inventory is a linked list on the heap. add allocates a node with malloc, copies the name safely with snprintf and puts it at the front of the list; the three nested calls in main build the whole inventory at once.

To save, main opens inventory.csv and writes one line per item with fprintf, with the fields separated by ;. If the file cannot be opened, it frees the list before leaving with code 1. After fclose, free_all frees every node: from then on, the data exists only in the file.

load goes the other way. fscanf reads each line with the format " %19[^;];%d;%lf": the leading space skips the previous newline, %19[^;] reads up to the semicolon and never more than 19 characters (what fits in name), and the loop carries on while all three fields are read. Each line becomes a new node through add.

Because add inserts at the front, the loaded list ends up in the reverse order of the file, which is why Screws x100 comes first. The report walks the list, flags anything with fewer than 5 units as REORDER and adds up the stock value inside the for itself.

Finally, free_all frees every node and remove deletes the test file. Write this program in DMarlon Studio's Console target and run it with F9: it is a good base for adding a menu, searches or sorting with qsort.

Code · main.c

#include <stdio.h>#include <stdlib.h>typedef struct Item { char name[20]; int qty; double price; struct Item *next; } Item;Item *add(Item *head, const char *name, int qty, double price) {  // a new node in front    Item *it = malloc(sizeof *it);    if (!it) exit(EXIT_FAILURE);    snprintf(it->name, sizeof it->name, "%s", name);    it->qty = qty; it->price = price; it->next = head;    return it;}void free_all(Item *it) { while (it) { Item *next = it->next; free(it); it = next; } }Item *load(const char *path) {  // reads the file into a new list; NULL if it cannot    FILE *f = fopen(path, "r");    if (!f) return NULL;    Item *head = NULL; char name[20]; int qty; double price;    while (fscanf(f, " %19[^;];%d;%lf", name, &qty, &price) == 3) head = add(head, name, qty, price);    fclose(f);    return head;}int main(void) {    Item *stock = add(add(add(NULL, "Screws x100", 40, 4.25), "Drill", 3, 59.00), "Hammer", 12, 9.90);    FILE *f = fopen("inventory.csv", "w");    if (!f) { free_all(stock); return 1; }    for (const Item *it = stock; it; it = it->next) fprintf(f, "%s;%d;%.2f\n", it->name, it->qty, it->price);    fclose(f); free_all(stock);  // now the data lives only in the file    stock = load("inventory.csv");    double total = 0;    for (const Item *it = stock; it; total += it->qty * it->price, it = it->next)        printf("%-12s %3d x %6.2f%s\n", it->name, it->qty, it->price, it->qty < 5 ? "  REORDER" : "");    printf("Stock value: %.2f\n", total);    free_all(stock); remove("inventory.csv");    return 0;}

Output · cc main.c -o main && ./main

Screws x100   40 x   4.25
Drill          3 x  59.00  REORDER
Hammer        12 x   9.90
Stock value: 465.80

Key points

  • The data lives in a linked list on the heap.
  • Saving to text and loading it back separates memory from the file.
  • %19[^;] reads up to a separator without overflowing the buffer.
  • Every malloc has its free: free_all before leaving, on errors too.

Exercise

Add int sell(Item *stock, const char *name, int units), which finds the item and takes the units off (returning -1 if it does not exist or there are not enough), and use it before saving to sell 2 hammers.