πŸ›’ Shopping Cart β€” Singly Linked List Project
0%
Mini Project  Β·  Singly Linked List  Β·  C Programming

πŸ›’ Shopping Cart
Singly Linked List

Build a fully working shopping cart using a singly linked list in C. Each item in the cart is a node. Adding items, removing items, showing totals β€” all done by pointer operations on the list. Five steps from struct design to the complete menu program.

S1
Node Design & What is a List
S2
addItem() β€” Insert at End
S3
displayCart() & getTotal()
S4
removeItem() β€” Delete by Name
S5
Complete Menu Program
Step 1 🧱 Node Design β€” What is a Singly Linked List?
S1
The Shopping Cart as a Chain of Nodes
Each item is a node. Each node knows the next item. The cart is just the first node.
Concept + Struct
Real World Analogy
Imagine a shopping cart where items are connected with a chain. Each item has a tag (name + price + quantity) and a hook that connects to the next item. The last item's hook has nothing attached β€” it is NULL. You only know where the cart starts β€” the head pointer. From the head you can reach every item by following the hooks one at a time.

That is a singly linked list: a chain of nodes where each node has data and a pointer to the next node. You can only travel forward β€” head β†’ item1 β†’ item2 β†’ item3 β†’ NULL.
Memory diagram β€” how nodes link in RAM
head pointer Node 1 name: "Apple" price:40 qty:2 next β†’ Node 2 name: "Milk" price:55 qty:1 next β†’ Node 3 name: "Bread" price:30 qty:3 next = NULL starts here chain ends here
Three fields in every cart node: name (the item name), price (per unit), qty (how many), and next (pointer to the next node). The cart itself is just Node *head β€” a single pointer to the first node. Everything else is reachable from head by following next pointers.
cart_node.c β€” struct definition
C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* ── The Node β€” one item in the shopping cart ── */
typedef struct Node {
    char   name[50];    /* item name e.g. "Apple"        */
    float  price;       /* price per unit e.g. 40.00     */
    int    qty;         /* quantity e.g. 2               */
    struct Node *next;  /* pointer to next item in cart  */
} Node;

/* ── The Cart β€” just the head pointer ── */
Node *head = NULL;   /* cart starts empty (NULL)      */

/* Create a new node on the heap */
Node* createNode(const char *name, float price, int qty) {
    Node *n = (Node*)malloc(sizeof(Node));
    strcpy(n->name, name);  /* copy name into node          */
    n->price = price;        /* set price                   */
    n->qty   = qty;          /* set quantity                */
    n->next  = NULL;        /* not yet connected           */
    return n;
}
Why heap (malloc), not stack (local variable)? A local variable dies when the function returns. The cart needs to survive across multiple function calls. malloc puts the node in heap memory which lives until you explicitly free() it.
Step 2 βž• addItem() β€” Insert a New Item at the End of the Cart
S2
addItem() β€” Walk to the Last Node, Attach New Node
If cart empty β†’ new node becomes head. Otherwise walk to end β†’ link it.
Insert at Tail
Adding an item means creating a new node and attaching it to the end of the chain. Two cases: empty cart β€” new node becomes head directly. Non-empty cart β€” walk from head following next pointers until you reach a node whose next == NULL (the last node), then set last->next = newNode. The new node always has next = NULL because it is now the last item.
addItem() β€” before and after inserting "Bread"
BEFORE addItem("Bread") head β†’Apple Apple β‚Ή40 Γ— 2 nextβ†’Milk Milk β‚Ή55 Γ— 1 next = NULL βœ– AFTER addItem("Bread") β€” tailβ†’next connected to new node head Apple β‚Ή40 Γ— 2 nextβ†’Milk Milk β‚Ή55 Γ— 1 nextβ†’Bread βœ… Bread β˜…NEW β‚Ή30 Γ— 3 next = NULL
addItem.c
C
/* Add item to end of cart β€” insert at tail */
void addItem(const char *name, float price, int qty) {

    Node *newNode = createNode(name, price, qty); /* make node */

    /* Case 1 β€” cart is empty: new node becomes head */
    if (head == NULL) {
        head = newNode;
        printf("  [+] '%s' added (cart was empty)\n", name);
        return;
    }

    /* Case 2 β€” walk to the last node */
    Node *current = head;
    while (current->next != NULL) {
        current = current->next;  /* move one step forward */
    }

    /* current is now the last node β€” attach new node */
    current->next = newNode;      /* link: last β†’ new     */
    printf("  [+] '%s' added (qty:%d @ Rs%.0f)\n",
            name, qty, price);
}

/* Quick test */
int main() {
    addItem("Apple",  40.0, 2);
    addItem("Milk",   55.0, 1);
    addItem("Bread",  30.0, 3);
    return 0;
}
output
  [+] 'Apple' added (cart was empty)
  [+] 'Milk' added (qty:1 @ Rs55)
  [+] 'Bread' added (qty:3 @ Rs30)
The walk pattern while(current->next != NULL) current = current->next; is the most fundamental linked list operation. It finds the tail in O(n) time. You will use this exact pattern in almost every linked list function.
Step 3 🧾 displayCart() & getTotal() β€” Traverse and Calculate
S3
displayCart() β€” Walk Every Node and Print. getTotal() β€” Accumulate Price.
Both functions traverse the full list from head to NULL β€” the core linked list pattern
Traversal
Traversal is the most common linked list operation: start at head, process the current node, move to current->next, repeat until NULL. displayCart() prints each item as a receipt row. getTotal() uses the same walk but accumulates price Γ— qty for each node into a running total and returns it.
display_total.c
C
/* Display all items β€” traverse head β†’ NULL */
void displayCart() {
    if (head == NULL) {
        printf("  Cart is empty!\n");
        return;
    }

    printf("\n  %-20s %8s  %5s  %10s\n",
           "Item", "Price", "Qty", "Subtotal");
    printf("  %s\n", "------------------------------------------------");

    Node *current = head;             /* start at head        */

    while (current != NULL) {         /* stop when NULL       */
        float sub = current->price * current->qty;
        printf("  %-20s %8.2f  %5d  %10.2f\n",
               current->name,
               current->price,
               current->qty,
               sub);
        current = current->next;      /* move to next node    */
    }

    printf("  %s\n", "------------------------------------------------");
}

/* Calculate total β€” same traversal, accumulate priceΓ—qty */
float getTotal() {
    float  total   = 0.0;
    Node  *current = head;

    while (current != NULL) {
        total  += current->price * current->qty; /* accumulate */
        current = current->next;
    }
    return total;
}

/* Count items */
int countItems() {
    int   count   = 0;
    Node *current = head;
    while (current != NULL) { count++; current = current->next; }
    return count;
}

int main() {
    addItem("Apple",  40.0, 2);
    addItem("Milk",   55.0, 1);
    addItem("Bread",  30.0, 3);
    addItem("Butter", 80.0, 1);

    displayCart();
    printf("  Items  : %d\n",   countItems());
    printf("  TOTAL  : Rs %.2f\n", getTotal());
    return 0;
}
output
  Item                    Price    Qty    Subtotal
  ------------------------------------------------
  Apple                   40.00      2       80.00
  Milk                    55.00      1       55.00
  Bread                   30.00      3       90.00
  Butter                  80.00      1       80.00
  ------------------------------------------------
  Items  : 4
  TOTAL  : Rs 305.00
All three functions β€” displayCart, getTotal, countItems β€” use the exact same traversal skeleton: Node *current = head; while(current != NULL) { ...process... current = current->next; }. This pattern is so common it becomes muscle memory. The only thing that changes is what you do inside the loop.
Step 4 ❌ removeItem() β€” Delete a Node by Name
S4
removeItem() β€” Find Node, Re-link Pointers, Free Memory
Three cases: remove head / remove middle / remove tail β€” pointer surgery
Delete Node
Deletion is the trickiest linked list operation. You cannot delete a node by itself β€” you need its predecessor (previous node) to re-link the chain. Strategy: keep a prev pointer one step behind current. When current->name matches: Case 1 (head) β€” move head forward. Case 2 (middle/tail) β€” set prev->next = current->next β€” this bypasses the node. Then free(current) to release the memory.
removeItem("Milk") — prev→next jumps over the deleted node
BEFORE β€” Apple β†’ Milk β†’ Bread head Apple nextβ†’Milk (prev) Milk βœ– nextβ†’Bread (current) Bread next=NULL AFTER β€” Apple.next jumps over Milk β†’ Bread. Milk freed. head Apple nextβ†’Bread βœ… prevβ†’next = currentβ†’next Bread next=NULL Milk free()'d
removeItem.c
C
/* Remove item by name β€” three cases */
void removeItem(const char *name) {
    if (head == NULL) {
        printf("  Cart is empty.\n");
        return;
    }

    Node *current = head;
    Node *prev    = NULL;   /* tracks the node BEFORE current */

    /* Walk until we find the name or reach end */
    while (current != NULL &&
           strcmp(current->name, name) != 0) {
        prev    = current;         /* prev follows one behind      */
        current = current->next;  /* current moves forward        */
    }

    /* Not found */
    if (current == NULL) {
        printf("  '%s' not in cart.\n", name);
        return;
    }

    /* Case 1 β€” deleting the head node */
    if (prev == NULL) {
        head = current->next;     /* head moves to next node      */
    }
    /* Case 2 β€” deleting middle or tail node */
    else {
        prev->next = current->next; /* bypass current node          */
    }

    printf("  [-] '%s' removed from cart.\n", current->name);
    free(current);               /* release memory β€” never skip! */
}

int main() {
    addItem("Apple",  40.0, 2);
    addItem("Milk",   55.0, 1);
    addItem("Bread",  30.0, 3);

    printf("Before removal:\n");
    displayCart();

    removeItem("Milk");         /* remove middle node */
    removeItem("Apple");        /* remove head node   */
    removeItem("Eggs");         /* not in cart        */

    printf("After removals:\n");
    displayCart();
    printf("  TOTAL: Rs %.2f\n", getTotal());
    return 0;
}
output
Before removal:
  Item                    Price    Qty    Subtotal
  ------------------------------------------------
  Apple                   40.00      2       80.00
  Milk                    55.00      1       55.00
  Bread                   30.00      3       90.00
  ------------------------------------------------
  [-] 'Milk' removed from cart.
  [-] 'Apple' removed from cart.
  'Eggs' not in cart.
After removals:
  Item                    Price    Qty    Subtotal
  ------------------------------------------------
  Bread                   30.00      3       90.00
  ------------------------------------------------
  TOTAL: Rs 90.00
Always free(current) after removal. If you re-link pointers but skip free(), the node still occupies heap memory β€” a memory leak. In a long-running program, leaked nodes accumulate and eventually crash the program. Every malloc must have a matching free.
Step 5 🏁 Complete Shopping Cart β€” Full Menu Program
S5
All Functions Together β€” Menu-Driven Complete Program
Add Β· Remove Β· Display Β· Total Β· Clear Β· all functions in one runnable file
Full Project
The complete program assembles all five functions plus a clearCart() that frees every node in sequence β€” walking the list and freeing one node at a time. A do-while menu loop keeps the program running until the user chooses Exit. This is a complete, compilable, fully working C program demonstrating every core singly linked list operation.
FunctionWhat it doesKey pointer operation
createNode()malloc a new node, fill fields, return pointermalloc(sizeof(Node))
addItem()Walk to tail, set tail->next = newNodeInsert at tail
displayCart()Traverse head→NULL, print each nodecurrent = current->next
getTotal()Traverse, accumulate priceΓ—qtySame traversal
countItems()Traverse, count++ each nodeSame traversal
removeItem()Find node, bypass with prev->next, free nodeprev->next = current->next; free(current)
clearCart()Free every node one by onetmp=current->next; free(current); current=tmp
shopping_cart_complete.c
C β€” Complete Project
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* ══════════════════════════════════════
   NODE DEFINITION
═══════════════════════════════════════ */
typedef struct Node {
    char   name[50];
    float  price;
    int    qty;
    struct Node *next;
} Node;

Node *head = NULL;   /* global head β€” empty cart */

/* ══════════════════════════════════════
   CREATE NODE
═══════════════════════════════════════ */
Node* createNode(const char *name, float price, int qty) {
    Node *n   = (Node*)malloc(sizeof(Node));
    strcpy(n->name, name);
    n->price  = price;
    n->qty    = qty;
    n->next   = NULL;
    return n;
}

/* ══════════════════════════════════════
   ADD ITEM β€” insert at tail
═══════════════════════════════════════ */
void addItem(const char *name, float price, int qty) {
    Node *newNode = createNode(name, price, qty);
    if (head == NULL) { head = newNode; }
    else {
        Node *curr = head;
        while (curr->next != NULL) curr = curr->next;
        curr->next = newNode;
    }
    printf("  [+] '%s' added (qty:%d @ Rs%.2f)\n", name, qty, price);
}

/* ══════════════════════════════════════
   DISPLAY CART β€” traverse & print
═══════════════════════════════════════ */
void displayCart() {
    if (head == NULL) { printf("  Cart is empty.\n"); return; }
    printf("\n  %-20s %8s %5s %10s\n","Item","Price","Qty","Subtotal");
    printf("  %-50s\n", "--------------------------------------------------");
    Node *curr = head;
    while (curr != NULL) {
        printf("  %-20s %8.2f %5d %10.2f\n",
               curr->name, curr->price, curr->qty,
               curr->price * curr->qty);
        curr = curr->next;
    }
    printf("  %-50s\n", "--------------------------------------------------");
}

/* ══════════════════════════════════════
   GET TOTAL
═══════════════════════════════════════ */
float getTotal() {
    float total = 0.0;
    Node *curr  = head;
    while (curr != NULL) { total += curr->price * curr->qty; curr = curr->next; }
    return total;
}

/* ══════════════════════════════════════
   REMOVE ITEM β€” find, bypass, free
═══════════════════════════════════════ */
void removeItem(const char *name) {
    Node *curr = head, *prev = NULL;
    while (curr != NULL && strcmp(curr->name, name) != 0) {
        prev = curr; curr = curr->next;
    }
    if (curr == NULL) { printf("  '%s' not in cart.\n", name); return; }
    if (prev == NULL) head = curr->next;  /* was head node   */
    else              prev->next = curr->next; /* middle/tail  */
    printf("  [-] '%s' removed. (was Rs%.2f Γ— %d)\n",
           curr->name, curr->price, curr->qty);
    free(curr);
}

/* ══════════════════════════════════════
   CLEAR CART β€” free all nodes
═══════════════════════════════════════ */
void clearCart() {
    Node *curr = head;
    while (curr != NULL) {
        Node *tmp = curr->next;  /* save next BEFORE freeing    */
        free(curr);               /* free current node           */
        curr = tmp;               /* move to saved next          */
    }
    head = NULL;
    printf("  Cart cleared.\n");
}

/* ══════════════════════════════════════
   MENU
═══════════════════════════════════════ */
void printMenu() {
    printf("\n  ╔══════════════════════════╗\n");
    printf("  β•‘   πŸ›’  SHOPPING CART     β•‘\n");
    printf("  ╠══════════════════════════╣\n");
    printf("  β•‘  1. Add Item             β•‘\n");
    printf("  β•‘  2. Remove Item          β•‘\n");
    printf("  β•‘  3. View Cart            β•‘\n");
    printf("  β•‘  4. Get Total            β•‘\n");
    printf("  β•‘  5. Clear Cart           β•‘\n");
    printf("  β•‘  6. Exit                 β•‘\n");
    printf("  β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n");
    printf("  Choice: ");
}

/* ══════════════════════════════════════
   MAIN
═══════════════════════════════════════ */
int main() {
    int   choice;
    char  name[50];
    float price;
    int   qty;

    /* Pre-load some items */
    addItem("Apple",  40.0, 2);
    addItem("Milk",   55.0, 1);
    addItem("Bread",  30.0, 3);

    do {
        printMenu();
        scanf("%d", &choice);
        getchar();  /* flush newline */

        switch (choice) {
            case 1:
                printf("  Name: ");  fgets(name, 50, stdin);
                name[strcspn(name, "\n")] = 0; /* remove newline */
                printf("  Price: "); scanf("%f", &price);
                printf("  Qty  : "); scanf("%d", &qty);
                getchar();
                addItem(name, price, qty);
                break;
            case 2:
                printf("  Remove item name: ");
                fgets(name, 50, stdin);
                name[strcspn(name, "\n")] = 0;
                removeItem(name);
                break;
            case 3:
                displayCart();
                break;
            case 4:
                displayCart();
                printf("  TOTAL: Rs %.2f\n", getTotal());
                break;
            case 5:
                clearCart();
                break;
            case 6:
                clearCart();  /* always free before exit */
                printf("  Goodbye! πŸ›’\n");
                break;
            default:
                printf("  Invalid choice.\n");
        }
    } while (choice != 6);

    return 0;
}
sample run
  [+] 'Apple' added (qty:2 @ Rs40.00)
  [+] 'Milk' added (qty:1 @ Rs55.00)
  [+] 'Bread' added (qty:3 @ Rs30.00)

  ╔══════════════════════════╗
  β•‘   πŸ›’  SHOPPING CART     β•‘
  ╠══════════════════════════╣
  β•‘  1. Add Item             β•‘
  β•‘  2. Remove Item          β•‘
  β•‘  3. View Cart            β•‘
  β•‘  4. Get Total            β•‘
  β•‘  5. Clear Cart           β•‘
  β•‘  6. Exit                 β•‘
  β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
  Choice: 4

  Item                    Price   Qty    Subtotal
  --------------------------------------------------
  Apple                   40.00     2       80.00
  Milk                    55.00     1       55.00
  Bread                   30.00     3       90.00
  --------------------------------------------------
  TOTAL: Rs 305.00

  Choice: 2
  Remove item name: Milk
  [-] 'Milk' removed. (was Rs55.00 Γ— 1)

  Choice: 4
  Item                    Price   Qty    Subtotal
  --------------------------------------------------
  Apple                   40.00     2       80.00
  Bread                   30.00     3       90.00
  --------------------------------------------------
  TOTAL: Rs 170.00

  Choice: 6
  Cart cleared.
  Goodbye! πŸ›’
clearCart() pattern: Node *tmp = curr->next; free(curr); curr = tmp; β€” you must save next before freeing, because after free(curr) the memory is gone and reading curr->next is undefined behaviour. Save next first, then free, then move.
checklist β€” tick each concept when understood
  • Node struct: name, price, qty, struct Node *next. Must use struct Node inside the struct. typedef lets you write Node* everywhere else. head = NULL means empty cart.
  • createNode / malloc: malloc(sizeof(Node)) allocates heap memory for one node. Heap memory survives across function calls. Must be free()'d eventually or it leaks.
  • addItem() β€” insert at tail: If head==NULL β†’ new node is head. Else walk: while(curr->next != NULL) curr = curr->next; then curr->next = newNode.
  • Traversal pattern: Node *curr = head; while(curr != NULL) { ...process... curr = curr->next; } β€” used by displayCart, getTotal, countItems, clearCart. The single most important linked list pattern.
  • removeItem() β€” prev pointer: Keep prev one step behind current. When found: if prev==NULL β†’ deleting head β†’ head = curr->next. Else prev->next = curr->next. Then free(curr).
  • clearCart() β€” save next before free: Node *tmp = curr->next; free(curr); curr = tmp; β€” never access curr->next after free(curr) β€” undefined behaviour.
  • Arrow operator (->): curr->name is shorthand for (*curr).name. When you have a pointer to a struct, use -> to access its fields.