/* * sample-program.c: a small, complete C program with numbered comments. * Free sample from 99helpers.com/file-types/c * * It prints a stock report for a few fictional shop items, sorted by value, * and flags items that are running low. * * Build and run on Linux or macOS (GCC or Clang): * cc -Wall -Wextra -std=c17 sample-program.c -o sample-program * ./sample-program (or ./sample-program 10 to change the threshold) * On Windows with Microsoft's compiler, in a Developer Command Prompt: * cl /W4 /std:c17 sample-program.c * sample-program.exe */ /* 1. Includes: the preprocessor pastes in these standard headers before * compiling. They declare printf, malloc, qsort, strtol and errno. */ #include #include #include /* 2. A macro: plain text substitution, done before the compiler proper sees * the code. This one counts the elements of an array. */ #define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0])) /* 3. A struct type groups related values; typedef gives it a short name. */ typedef struct { const char *name; int stock; double price; } Item; /* 4. A constant array at file scope. `static` keeps the name private to this * file, so it can't clash with a `catalogue` in another .c file. */ static const Item catalogue[] = { {"Notebook", 12, 3.50}, {"Pencil", 40, 0.80}, {"Stapler", 2, 7.25}, {"Ruler", 0, 1.20}, {"Glue stick", 5, 1.95}, }; /* 5. A function. It takes a pointer to a constant Item, so it can read the * item without copying it and promises not to change it. */ static double stock_value(const Item *item) { return item->stock * item->price; } /* 6. A comparison function for qsort. qsort only knows about bytes, so it * passes untyped `const void *` pointers that we convert back. */ static int by_value_desc(const void *a, const void *b) { double va = stock_value(*(const Item *const *)a); double vb = stock_value(*(const Item *const *)b); return (va < vb) - (va > vb); } /* 7. main: where every C program starts. argc is the number of command-line * arguments and argv holds them as strings; argv[0] is the program name. */ int main(int argc, char *argv[]) { long threshold = 5; /* 8. Reading a number from the command line safely: strtol reports * errors, where atoi would silently return 0 for "abc". */ if (argc > 1) { char *end; errno = 0; threshold = strtol(argv[1], &end, 10); if (errno != 0 || end == argv[1] || *end != '\0' || threshold < 0) { fprintf(stderr, "usage: %s [low-stock-threshold]\n", argv[0]); return EXIT_FAILURE; } } /* 9. Memory from the heap: malloc returns NULL on failure, and every * malloc needs exactly one free. Here we sort pointers, not items. */ size_t count = ARRAY_LEN(catalogue); const Item **sorted = malloc(count * sizeof *sorted); if (sorted == NULL) { perror("malloc"); return EXIT_FAILURE; } for (size_t i = 0; i < count; i++) { sorted[i] = &catalogue[i]; } qsort(sorted, count, sizeof *sorted, by_value_desc); /* 10. Formatted output: %-12s pads a string to 12 characters, %8.2f * prints a number with two decimals in 8 columns. */ printf("%-12s %5s %7s %8s\n", "Item", "Stock", "Price", "Value"); double total = 0.0; int low = 0; for (size_t i = 0; i < count; i++) { const Item *it = sorted[i]; int is_low = it->stock < threshold; total += stock_value(it); low += is_low; printf("%-12s %5d %7.2f %8.2f%s\n", it->name, it->stock, it->price, stock_value(it), is_low ? " low" : ""); } printf("Total stock value: %.2f\n", total); printf("Items below %ld in stock: %d\n", threshold, low); free(sorted); /* 11. The return value of main is the exit status: 0 (EXIT_SUCCESS) * means success to the shell, a script or a build tool. */ return EXIT_SUCCESS; }