๐Ÿ›’ Grocery Billing System โ€” Mini Project
0%
Mini Project  ยท  Structs ยท Arrays ยท Pointers ยท Functions

๐Ÿ›’ Grocery Billing System
Mini Project in C

A real shop counter in C. Define a product struct. Load an inventory. Add items to cart. Apply discounts and tax. Print a formatted bill. Six focused build steps โ€” every struct, pointer, and function concept used for a genuine purpose.

typedef struct array of structs const struct * pointer modify strstr search function pointer
S1
Struct Setup
S2
Display Shop
S3
Add to Cart
S4
Generate Bill
S5
Search & Stock
S6
Full Program

๐Ÿ›’  Project Overview โ€” What We Are Building

A grocery shop billing system. The shop has an inventory of products stored in a struct array โ€” each product has a name, price, category, and stock. A customer adds items to a cart (another struct array). The system generates a formatted bill with subtotal, GST tax, and loyalty discount. Every major C concept โ€” struct, pointer, array, function, function pointer โ€” appears in a real, working role.

Product struct โ€” inventory CartItem struct โ€” customer cart const struct* โ€” read-only display struct* โ€” modify stock in-place strstr โ€” product search function pointer โ€” bill style
data flow through the billing system
Product shop[]
โ†’
addToCart(*shop,*cart)
โ†’
CartItem cart[]
โ†’
calcTotal(*cart)
โ†’
printBill(*cart,fn)

Two struct arrays โ€” inventory and cart โ€” communicate through pointer functions. Stock decreases when items are added. The bill function is pluggable via function pointer.

StructFieldsRoleHow accessed
Productname, category, price, stockShop inventory โ€” 8 productsconst Product* for display, Product* to update stock
CartItemname, price, qty, subtotalCustomer's basketCartItem* to add items, const CartItem* for bill
step 1 โ€” struct setup
S1
๐Ÿ—๏ธ Product & CartItem Structs โ€” Designing the Data
Two typedef structs โ€” Product for the shop inventory, CartItem for the customer basket
Struct Design
Before writing any function, we design the data. A Product struct models one item on the shop shelf โ€” its name, category, price per unit, and how many units are in stock. A CartItem models what goes into the customer's basket โ€” the product name, unit price, quantity chosen, and the computed subtotal. Two separate struct types because the shop's permanent inventory and the temporary customer cart have different purposes and different lifetimes.
s1_struct_setup.c
C
#include <stdio.h>
#include <string.h>

#define MAX_PRODUCTS  8
#define MAX_CART      10
#define GST_RATE      0.05f    /* 5% GST                    */
#define DISC_THRESHOLD 500.0f  /* 10% off if bill > Rs 500  */

/* โ”€โ”€ PRODUCT โ€” one item on the shop shelf โ”€โ”€ */
typedef struct {
    char  name[30];      /* "Basmati Rice 1kg"    */
    char  category[15]; /* "Grains"              */
    float price;          /* price per unit in Rs  */
    int   stock;          /* units available        */
} Product;

/* โ”€โ”€ CART ITEM โ€” what customer picks โ”€โ”€ */
typedef struct {
    char  name[30];
    float unitPrice;
    int   qty;
    float subtotal;       /* unitPrice * qty       */
} CartItem;

/* โ”€โ”€ SHOP INVENTORY โ€” 8 products โ”€โ”€ */
Product initShop() {
    /* Returned for illustration โ€” in main we use array directly */
    Product p = {"Basmati Rice 1kg", "Grains", 75.0f, 50};
    return p;
}

int main() {
    /* Full inventory โ€” array of 8 Product structs */
    Product shop[MAX_PRODUCTS] = {
        {"Basmati Rice 1kg",  "Grains",   75.0f,  50},
        {"Toor Dal 500g",     "Pulses",   65.0f,  40},
        {"Sunflower Oil 1L",  "Oils",     140.0f, 30},
        {"Whole Wheat Atta",  "Grains",   55.0f,  60},
        {"Amul Butter 100g",  "Dairy",    52.0f,  25},
        {"Full Cream Milk 1L","Dairy",    68.0f,  35},
        {"Turmeric Powder",   "Spices",   30.0f,  80},
        {"Sugar 1kg",         "Essentials",42.0f, 70}
    };

    printf("sizeof(Product)  = %zu bytes\n", sizeof(Product));
    printf("sizeof(CartItem) = %zu bytes\n", sizeof(CartItem));
    printf("Shop loaded with %d products.\n", MAX_PRODUCTS);
    printf("First product: %s @ Rs %.2f (stock: %d)\n",
           shop[0].name, shop[0].price, shop[0].stock);
    return 0;
}
output
sizeof(Product)  = 52 bytes
sizeof(CartItem) = 48 bytes
Shop loaded with 8 products.
First product: Basmati Rice 1kg @ Rs 75.00 (stock: 50)
Two structs, two purposes. Product is permanent โ€” it lives for the entire program and tracks real inventory. CartItem is per-transaction โ€” it only holds what the customer picked. Keeping them separate makes the code clean: display functions take const Product*, billing functions take const CartItem*.
step 2 โ€” display shop
S2
๐Ÿ–ฅ๏ธ displayShop() โ€” const Product* Walk, Category Filter
Read-only pointer walk through inventory โ€” formatted table โ€” filter by category
const struct*
Two display functions โ€” both use const Product *shop because they only read. displayAll prints every product in a formatted table with a numbered index. displayByCategory walks the same array with a pointer, using strcmp to match the category and skipping non-matches. Passing const pointer means even if someone accidentally tries to write shop[i].stock = 0 inside these functions, the compiler refuses.
s2_display.c
C
#include <stdio.h>
#include <string.h>

typedef struct{char name[30];char category[15];float price;int stock;}Product;

/* Display all products โ€” const: read-only */
void displayAll(const Product *shop, int n) {
    printf("\n%-3s %-22s %-12s %7s %6s\n",
           "No","Product","Category","Price","Stock");
    printf("%-3s %-22s %-12s %7s %6s\n",
           "---","----------------------","------------","-------","------");

    for (int i = 0; i < n; i++) {
        printf("%-3d %-22s %-12s %7.2f %6d",
               i+1, shop[i].name, shop[i].category,
               shop[i].price, shop[i].stock);
        if (shop[i].stock < 10) printf("  *** LOW");
        printf("\n");
    }
}

/* Display by category โ€” skip non-matching */
void displayByCategory(const Product *shop, int n,
                        const char *cat) {
    printf("\n--- Category: %s ---\n", cat);
    int found = 0;
    for (int i = 0; i < n; i++) {
        if (strcmp(shop[i].category, cat) != 0) continue;
        printf("  %-22s Rs %7.2f  (stock: %d)\n",
               shop[i].name, shop[i].price, shop[i].stock);
        found++;
    }
    if (!found) printf("  No products in this category.\n");
}

int main() {
    Product shop[] = {
        {"Basmati Rice 1kg", "Grains",   75.0f, 50},
        {"Toor Dal 500g",    "Pulses",   65.0f, 40},
        {"Sunflower Oil 1L", "Oils",    140.0f, 7},
        {"Whole Wheat Atta", "Grains",   55.0f, 60},
        {"Amul Butter 100g", "Dairy",    52.0f, 25},
        {"Full Cream Milk 1L","Dairy",   68.0f, 8},
        {"Turmeric Powder",  "Spices",   30.0f, 80},
        {"Sugar 1kg",        "Essentials",42.0f,70}
    };
    displayAll(shop, 8);
    displayByCategory(shop, 8, "Dairy");
    return 0;
}
output
No  Product                Category      Price  Stock
--- ---------------------- ------------ ------- ------
1   Basmati Rice 1kg       Grains        75.00     50
2   Toor Dal 500g          Pulses        65.00     40
3   Sunflower Oil 1L       Oils         140.00      7  *** LOW
4   Whole Wheat Atta       Grains        55.00     60
5   Amul Butter 100g       Dairy         52.00     25
6   Full Cream Milk 1L     Dairy         68.00      8  *** LOW
7   Turmeric Powder        Spices        30.00     80
8   Sugar 1kg              Essentials    42.00     70

--- Category: Dairy ---
  Amul Butter 100g         Rs   52.00  (stock: 25)
  Full Cream Milk 1L       Rs   68.00  (stock: 8)
One walk, two jobs. The low-stock alert if(stock < 10) adds a warning to the same row without a second loop. This is the pointer walk advantage โ€” you process each element once and do everything you need in a single pass.
step 3 โ€” add to cart
S3
๐Ÿ›’ addToCart() โ€” struct* Modifies Both Inventory and Cart
Validate stock via Product* โ€” fill CartItem โ€” decrement stock in-place
Pointer Modify
Adding an item to the cart requires two pointer operations at once. We receive Product *shop (not const โ€” because we need to reduce stock) and CartItem *cart (to fill a new cart slot). After validating the product exists and has enough stock, we: copy the product name and price into a new CartItem, set the quantity, compute the subtotal, then decrement the stock on the original product through the pointer. Both the inventory and the cart are updated in one function call.
s3_add_to_cart.c
C
#include <stdio.h>
#include <string.h>

typedef struct{char name[30];char category[15];float price;int stock;}Product;
typedef struct{char name[30];float unitPrice;int qty;float subtotal;}CartItem;

/* Returns 1 on success, 0 on failure
   Modifies shop[idx].stock AND fills cart[*cartCount] */
int addToCart(Product *shop, int shopSize,
               CartItem *cart, int *cartCount,
               int productIdx, int qty) {

    /* Validate index */
    if (productIdx < 0 || productIdx >= shopSize) {
        printf("  Invalid product number.\n");
        return 0;
    }

    Product *p = &shop[productIdx];   /* pointer to chosen product */

    /* Validate stock */
    if (p->stock < qty) {
        printf("  Sorry! Only %d units of %s in stock.\n",
               p->stock, p->name);
        return 0;
    }

    /* Validate cart space */
    if (*cartCount >= 10) {
        printf("  Cart is full (max 10 items).\n");
        return 0;
    }

    /* Fill cart slot via pointer */
    CartItem *slot = &cart[*cartCount];
    strncpy(slot->name, p->name, 29);
    slot->unitPrice = p->price;
    slot->qty       = qty;
    slot->subtotal  = p->price * qty;

    /* Deduct stock from real inventory โ€” non-const pointer */
    p->stock -= qty;

    (*cartCount)++;   /* advance cart counter via pointer */

    printf("  Added: %s x%d = Rs %.2f\n",
           slot->name, qty, slot->subtotal);
    return 1;
}

void showCart(const CartItem *cart, int n) {
    printf("\n--- Cart (%d items) ---\n", n);
    for(int i=0;i<n;i++)
        printf("  %-22s x%-3d Rs %.2f\n",
               cart[i].name, cart[i].qty, cart[i].subtotal);
}

int main() {
    Product shop[] = {
        {"Basmati Rice 1kg", "Grains",  75.0f, 50},
        {"Toor Dal 500g",   "Pulses",  65.0f, 40},
        {"Sunflower Oil 1L","Oils",   140.0f,  3},
        {"Amul Butter 100g","Dairy",   52.0f, 25}
    };
    CartItem cart[10];
    int cartCount = 0;

    printf("=== Customer Shopping ===\n");
    addToCart(shop, 4, cart, &cartCount, 0, 2);  /* Rice x2    */
    addToCart(shop, 4, cart, &cartCount, 1, 1);  /* Dal x1     */
    addToCart(shop, 4, cart, &cartCount, 2, 5);  /* Oil x5 โ€” fail */
    addToCart(shop, 4, cart, &cartCount, 2, 2);  /* Oil x2     */

    showCart(cart, cartCount);

    printf("\nStock after shopping:\n");
    printf("  Rice stock now: %d\n", shop[0].stock);
    printf("  Oil  stock now: %d\n", shop[2].stock);
    return 0;
}
output
=== Customer Shopping ===
  Added: Basmati Rice 1kg x2 = Rs 150.00
  Added: Toor Dal 500g x1 = Rs 65.00
  Sorry! Only 3 units of Sunflower Oil 1L in stock.
  Added: Sunflower Oil 1L x2 = Rs 280.00

--- Cart (3 items) ---
  Basmati Rice 1kg       x2    Rs 150.00
  Toor Dal 500g          x1    Rs 65.00
  Sunflower Oil 1L       x2    Rs 280.00

Stock after shopping:
  Rice stock now: 48
  Oil  stock now: 1
Why int *cartCount not int cartCount? The function must increment the caller's counter. Passing by value would give the function a copy โ€” the caller would never see the count increase. Passing &cartCount and incrementing via (*cartCount)++ updates the real counter in main.
step 4 โ€” generate bill
S4
๐Ÿงพ generateBill() โ€” Subtotal, GST, Discount, Grand Total
const CartItem* walk โ€” compute all totals โ€” function pointer for bill style
Bill + fn ptr
The billing function walks the cart with a const CartItem* pointer โ€” it only reads. It computes the subtotal by summing all item.subtotal values, applies 5% GST, then applies a 10% loyalty discount if the subtotal exceeds Rs 500. A function pointer selects between a detailed bill format and a compact receipt โ€” same calculation, pluggable output style.
s4_generate_bill.c
C
#include <stdio.h>
#include <time.h>

typedef struct{char name[30];float unitPrice;int qty;float subtotal;}CartItem;
#define GST_RATE        0.05f
#define DISC_THRESHOLD  500.0f
#define DISC_RATE       0.10f

/* Compute grand total โ€” returns via output pointers */
float calcTotal(const CartItem *cart, int n,
                float *gstOut, float *discOut) {
    float subtotal = 0;
    for (int i = 0; i < n; i++)
        subtotal += cart[i].subtotal;

    *discOut = (subtotal > DISC_THRESHOLD)
               ? subtotal * DISC_RATE : 0.0f;
    *gstOut  = (subtotal - *discOut) * GST_RATE;

    return subtotal - *discOut + *gstOut;
}

/* Detailed bill โ€” itemised */
void printDetailed(const CartItem *cart, int n,
                    float grand, float gst, float disc) {
    time_t now = time(NULL);
    printf("\n================================================\n");
    printf("           ANANTA GROCERY STORE\n");
    printf("           %s", ctime(&now));
    printf("================================================\n");
    printf("%-22s %5s %10s\n","Item","Qty","Amount");
    printf("------------------------------------------------\n");

    float subtotal = 0;
    for (int i = 0; i < n; i++) {
        printf("%-22s %5d %10.2f\n",
               cart[i].name, cart[i].qty, cart[i].subtotal);
        subtotal += cart[i].subtotal;
    }

    printf("------------------------------------------------\n");
    printf("%-27s %10.2f\n", "Subtotal", subtotal);
    if (disc > 0)
        printf("%-27s %10.2f\n", "Loyalty Discount (10%)", -disc);
    printf("%-27s %10.2f\n", "GST (5%)", gst);
    printf("================================================\n");
    printf("%-27s %10.2f\n", "GRAND TOTAL", grand);
    printf("================================================\n");
    printf("     Thank you for shopping with us!\n");
    printf("================================================\n");
}

/* Compact receipt */
void printCompact(const CartItem *cart, int n,
                   float grand, float gst, float disc) {
    printf("\n[RECEIPT] Items:%d  GST:%.2f  Disc:%.2f  TOTAL: Rs %.2f\n",
           n, gst, disc, grand);
}

int main() {
    CartItem cart[] = {
        {"Basmati Rice 1kg", 75.0f,  3, 225.0f},
        {"Toor Dal 500g",   65.0f,  2, 130.0f},
        {"Sunflower Oil 1L",140.0f, 2, 280.0f},
        {"Sugar 1kg",       42.0f,  1,  42.0f}
    };
    int n = 4;

    float gst, disc;
    float grand = calcTotal(cart, n, &gst, &disc);

    /* Function pointer โ€” swap bill style */
    void (*printBill)(const CartItem*, int,
                      float, float, float) = printDetailed;
    printBill(cart, n, grand, gst, disc);

    printf("\n--- Compact mode ---\n");
    printBill = printCompact;        /* swap โ€” same call */
    printBill(cart, n, grand, gst, disc);
    return 0;
}
output
================================================
           ANANTA GROCERY STORE
           Fri Jul 04 14:30:00 2026
================================================
Item                     Qty     Amount
------------------------------------------------
Basmati Rice 1kg           3     225.00
Toor Dal 500g              2     130.00
Sunflower Oil 1L           2     280.00
Sugar 1kg                  1      42.00
------------------------------------------------
Subtotal                          677.00
Loyalty Discount (10%)            -67.70
GST (5%)                           30.47
================================================
GRAND TOTAL                       639.77
================================================
     Thank you for shopping with us!
================================================

--- Compact mode ---
[RECEIPT] Items:4  GST:30.47  Disc:67.70  TOTAL: Rs 639.77
Output pointers for multiple return values. calcTotal needs to return three values โ€” grand total, GST, and discount. C functions return only one value, so we pass float *gstOut and float *discOut as output parameters. The function writes through these pointers and the caller reads the results from gst and disc after the call.
step 5 โ€” search and stock
S5
๐Ÿ” searchProduct() + restockItem() โ€” strstr & Pointer Modify
strstr searches name โ€” non-const pointer updates stock โ€” low stock report
Search + Restock
Two management functions. searchProduct uses strstr(shop[i].name, keyword) to find partial name matches โ€” type "Rice" and it finds "Basmati Rice 1kg". It returns a pointer to the found product so the caller can use it directly. restockItem takes a non-const Product* and adds to the stock directly โ€” and a lowStockReport walks the array printing every item where stock has fallen below the threshold.
s5_search_stock.c
C
#include <stdio.h>
#include <string.h>

typedef struct{char name[30];char category[15];float price;int stock;}Product;

/* Search โ€” partial name match via strstr
   Returns pointer to product or NULL */
Product* searchProduct(Product *shop, int n,
                        const char *keyword) {
    printf("\nSearching for \"%s\"...\n", keyword);
    for (int i = 0; i < n; i++) {
        if (strstr(shop[i].name, keyword)) {
            printf("  Found: %s @ Rs %.2f (stock: %d)\n",
                   shop[i].name, shop[i].price, shop[i].stock);
            return &shop[i];   /* pointer into real array */
        }
    }
    printf("  Not found.\n");
    return NULL;
}

/* Restock โ€” non-const pointer, modifies stock */
void restockItem(Product *p, int qty) {
    if (!p) { printf("  No product to restock.\n"); return; }
    p->stock += qty;
    printf("  Restocked: %s. New stock: %d\n",
           p->name, p->stock);
}

/* Low stock report โ€” walk and flag */
int lowStockReport(const Product *shop, int n, int threshold) {
    printf("\n=== LOW STOCK REPORT (below %d units) ===\n", threshold);
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (shop[i].stock < threshold) {
            printf("  %-22s stock: %d  [REORDER]\n",
                   shop[i].name, shop[i].stock);
            count++;
        }
    }
    if (!count) printf("  All products well-stocked.\n");
    return count;
}

/* Update price โ€” modify through pointer */
void updatePrice(Product *p, float newPrice) {
    if (!p) return;
    printf("  Price update: %s  Rs %.2f โ†’ Rs %.2f\n",
           p->name, p->price, newPrice);
    p->price = newPrice;
}

int main() {
    Product shop[] = {
        {"Basmati Rice 1kg", "Grains",   75.0f, 4},
        {"Toor Dal 500g",   "Pulses",   65.0f, 40},
        {"Sunflower Oil 1L","Oils",    140.0f, 2},
        {"Amul Butter 100g","Dairy",    52.0f, 7},
        {"Sugar 1kg",       "Essentials",42.0f,70}
    };

    /* Search returns pointer โ€” use it directly */
    Product *found = searchProduct(shop, 5, "Rice");
    restockItem(found, 50);
    updatePrice(found, 79.0f);

    searchProduct(shop, 5, "Oil");

    lowStockReport(shop, 5, 10);
    return 0;
}
output
Searching for "Rice"...
  Found: Basmati Rice 1kg @ Rs 75.00 (stock: 4)
  Restocked: Basmati Rice 1kg. New stock: 54
  Price update: Basmati Rice 1kg  Rs 75.00 โ†’ Rs 79.00

Searching for "Oil"...
  Found: Sunflower Oil 1L @ Rs 140.00 (stock: 2)

=== LOW STOCK REPORT (below 10 units) ===
  Sunflower Oil 1L       stock: 2  [REORDER]
  Amul Butter 100g       stock: 7  [REORDER]
Returning a pointer into the array means found points at the real shop[0]. Calling restockItem(found, 50) and updatePrice(found, 79.0f) modifies the actual inventory โ€” not a copy. This is the most efficient pattern for find-then-modify operations.
step 6 โ€” complete program
S6
๐Ÿ Complete Grocery Billing System โ€” Full Menu App
All functions + switch menu โ€” display, shop, bill, search, restock โ€” one complete program
Full Program
Every function from Steps 1โ€“5 combined into one complete, menu-driven billing system. The shop inventory persists across menu choices within the same session โ€” stock reduces when items are added to cart, and restocking updates the same array. The bill uses the function pointer โ€” you can switch between detailed and compact modes.
grocery_billing.c โ€” Complete Project
C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define MAX_PRODUCTS    8
#define MAX_CART        10
#define GST_RATE        0.05f
#define DISC_THRESHOLD  500.0f
#define DISC_RATE       0.10f
#define LOW_STOCK_LIMIT 10

typedef struct {
    char  name[30];
    char  category[15];
    float price;
    int   stock;
} Product;

typedef struct {
    char  name[30];
    float unitPrice;
    int   qty;
    float subtotal;
} CartItem;

/* โ”€โ”€ DISPLAY โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */
void displayAll(const Product *s, int n) {
    printf("\n%-3s %-22s %-12s %7s %6s\n",
           "No","Product","Category","Price","Stock");
    printf("%-55s\n","-------------------------------------------------------");
    for(int i=0;i<n;i++){
        printf("%-3d %-22s %-12s %7.2f %6d%s\n",
               i+1,s[i].name,s[i].category,s[i].price,s[i].stock,
               s[i].stock<LOW_STOCK_LIMIT?" **LOW":"");
    }
}

/* โ”€โ”€ ADD TO CART โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */
int addToCart(Product *shop, int shopSz,
               CartItem *cart, int *cnt,
               int idx, int qty) {
    if(idx<0||idx>=shopSz){printf("  Invalid.\n");return 0;}
    Product *p=&shop[idx];
    if(p->stock<qty){
        printf("  Only %d units of %s available.\n",p->stock,p->name);
        return 0;
    }
    if(*cnt>=MAX_CART){printf("  Cart full.\n");return 0;}
    CartItem *slot=&cart[*cnt];
    strncpy(slot->name,p->name,29);
    slot->unitPrice=p->price;
    slot->qty=qty;
    slot->subtotal=p->price*qty;
    p->stock-=qty;
    (*cnt)++;
    printf("  Added: %s x%d = Rs %.2f\n",
           slot->name,qty,slot->subtotal);
    return 1;
}

/* โ”€โ”€ SHOW CART โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */
void showCart(const CartItem *c, int n) {
    if(!n){printf("\n  Cart is empty.\n");return;}
    printf("\n--- Cart (%d items) ---\n",n);
    for(int i=0;i<n;i++)
        printf("  %-22s x%-3d Rs %.2f\n",
               c[i].name,c[i].qty,c[i].subtotal);
}

/* โ”€โ”€ BILLING โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */
float calcTotal(const CartItem *c,int n,
                float *g,float *d){
    float sub=0;
    for(int i=0;i<n;i++) sub+=c[i].subtotal;
    *d=(sub>DISC_THRESHOLD)?sub*DISC_RATE:0;
    *g=(sub-*d)*GST_RATE;
    return sub-*d+*g;
}

void printDetailed(const CartItem *c,int n,
                    float grand,float gst,float disc){
    time_t now=time(NULL);
    float sub=0;
    printf("\n================================================\n"
           "           ANANTA GROCERY STORE\n"
           "           %s"
           "================================================\n"
           "%-22s %5s %10s\n"
           "------------------------------------------------\n",
           ctime(&now),"Item","Qty","Amount");
    for(int i=0;i<n;i++){
        printf("%-22s %5d %10.2f\n",c[i].name,c[i].qty,c[i].subtotal);
        sub+=c[i].subtotal;
    }
    printf("------------------------------------------------\n"
           "%-27s %10.2f\n","Subtotal",sub);
    if(disc>0)
        printf("%-27s %10.2f\n","Loyalty Discount (10%)",-disc);
    printf("%-27s %10.2f\n"
           "================================================\n"
           "%-27s %10.2f\n"
           "================================================\n"
           "     Thank you for shopping with us!\n"
           "================================================\n",
           "GST (5%)",gst,"GRAND TOTAL",grand);
}

/* โ”€โ”€ SEARCH โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */
Product* searchProduct(Product *s,int n,const char *kw){
    for(int i=0;i<n;i++)
        if(strstr(s[i].name,kw)){
            printf("  Found: %s @ Rs%.2f stock:%d\n",
                   s[i].name,s[i].price,s[i].stock);
            return &s[i];
        }
    printf("  \"%s\" not found.\n",kw);
    return NULL;
}

/* โ”€โ”€ LOW STOCK โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */
void lowStockReport(const Product *s,int n){
    int cnt=0;
    printf("\n=== LOW STOCK REPORT ===\n");
    for(int i=0;i<n;i++)
        if(s[i].stock<LOW_STOCK_LIMIT){
            printf("  %-22s stock:%d [REORDER]\n",s[i].name,s[i].stock);
            cnt++;
        }
    if(!cnt)printf("  All products well-stocked.\n");
}

/* โ”€โ”€ MENU โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */
void showMenu(){
    printf("\nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—\n"
           "โ•‘   ๐Ÿ›’ ANANTA GROCERY STORE   โ•‘\n"
           "โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ\n"
           "โ•‘  1. View all products        โ•‘\n"
           "โ•‘  2. Add item to cart         โ•‘\n"
           "โ•‘  3. View cart                โ•‘\n"
           "โ•‘  4. Generate bill            โ•‘\n"
           "โ•‘  5. Search product           โ•‘\n"
           "โ•‘  6. Low stock report         โ•‘\n"
           "โ•‘  7. Clear cart               โ•‘\n"
           "โ•‘  8. Exit                     โ•‘\n"
           "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n"
           "Choice: ");
}

int main() {
    Product shop[MAX_PRODUCTS] = {
        {"Basmati Rice 1kg", "Grains",    75.0f, 50},
        {"Toor Dal 500g",   "Pulses",    65.0f, 40},
        {"Sunflower Oil 1L","Oils",     140.0f,  7},
        {"Whole Wheat Atta","Grains",    55.0f, 60},
        {"Amul Butter 100g","Dairy",     52.0f, 25},
        {"Full Cream Milk 1L","Dairy",   68.0f,  8},
        {"Turmeric Powder", "Spices",    30.0f, 80},
        {"Sugar 1kg",       "Essentials",42.0f, 70}
    };
    CartItem cart[MAX_CART];
    int cartCount = 0, choice;

    do {
        showMenu();
        scanf("%d",&choice); getchar();
        switch(choice){
            case 1: displayAll(shop,MAX_PRODUCTS); break;
            case 2: {
                displayAll(shop,MAX_PRODUCTS);
                int idx,qty;
                printf("Product number: "); scanf("%d",&idx); getchar();
                printf("Quantity      : "); scanf("%d",&qty); getchar();
                addToCart(shop,MAX_PRODUCTS,cart,&cartCount,idx-1,qty);
                break;
            }
            case 3: showCart(cart,cartCount); break;
            case 4: {
                if(!cartCount){printf("  Cart is empty.\n");break;}
                float gst,disc;
                float grand=calcTotal(cart,cartCount,&gst,&disc);
                printDetailed(cart,cartCount,grand,gst,disc);
                break;
            }
            case 5: {
                char kw[30];
                printf("Search keyword: ");
                fgets(kw,sizeof(kw),stdin);
                kw[strcspn(kw,"\n")]='\0';
                searchProduct(shop,MAX_PRODUCTS,kw);
                break;
            }
            case 6: lowStockReport(shop,MAX_PRODUCTS); break;
            case 7: cartCount=0;
                     printf("  Cart cleared.\n"); break;
            case 8: printf("  Thank you! Goodbye.\n"); break;
            default: printf("  Invalid choice.\n");
        }
    } while(choice!=8);
    return 0;
}
sample session
โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘   ๐Ÿ›’ ANANTA GROCERY STORE   โ•‘
โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
โ•‘  1. View all products        โ•‘
...
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Choice: 2
Product number: 1   (Basmati Rice 1kg)
Quantity      : 3
  Added: Basmati Rice 1kg x3 = Rs 225.00

Choice: 2
Product number: 3   (Sunflower Oil 1L)
Quantity      : 2
  Added: Sunflower Oil 1L x2 = Rs 280.00

Choice: 4
================================================
           ANANTA GROCERY STORE
           Fri Jul 04 14:30:00 2026
================================================
Item                     Qty     Amount
------------------------------------------------
Basmati Rice 1kg           3     225.00
Sunflower Oil 1L           2     280.00
------------------------------------------------
Subtotal                          505.00
Loyalty Discount (10%)            -50.50
GST (5%)                           22.73
================================================
GRAND TOTAL                       477.23
================================================
     Thank you for shopping with us!
checklist โ€” tick each concept when understood
  • S1 โ€” Struct Design: Two separate structs โ€” Product for inventory (permanent), CartItem for basket (per-transaction). sizeof shows exact memory. Array of structs initialised with brace notation.
  • S2 โ€” const Struct Pointer: const Product *shop โ€” read-only walk. Compiler blocks accidental writes. Category filter via strcmp + continue. Low-stock alert in same loop pass.
  • S3 โ€” Pointer Modify: addToCart takes non-const Product* to reduce stock and CartItem* to fill slot. int *cartCount โ€” pass address to let function increment caller's counter. Both arrays modified in one call.
  • S4 โ€” Bill + Function Pointer: calcTotal returns grand total and writes GST + discount via output pointers. void (*printBill)(...) holds either printDetailed or printCompact. Swap by reassigning โ€” same call, different output.
  • S5 โ€” Search + Return Pointer: strstr(name, keyword) for partial match. return &shop[i] โ€” gives caller pointer into real array. Modifying through returned pointer changes actual inventory. lowStockReport uses const pointer for read-only walk.
  • S6 โ€” Full Program: do-while menu loop. getchar() clears input buffer after scanf. Stock persists across menu choices โ€” same array throughout. Cart cleared by resetting cartCount = 0 โ€” no need to zero the data.