Elective Programming In C

Programming In CUnit 1415 min read

Practical C Programming: Problem Solving & Applications

Unit 14 of Programming In C bridges theory to real-world problem-solving, covering algorithm design, debugging, and practical applications like file handling, dynamic memory, and modular programming—essential for exams and industry projects.

TAKEAWAYS:

  • Learn to translate real-world problems into structured C programs using loops, arrays, and functions.
  • Master debugging techniques (logical errors, syntax, runtime) and testing strategies (unit testing, edge cases).
  • Understand modular design (header files, scope rules) to build scalable programs.
  • Apply file handling and dynamic memory to solve problems like data storage and memory-efficient operations.
  • Compare algorithmic approaches (e.g., sorting, searching) for efficiency in exams and projects.
  • Use practical examples (e.g., bank transactions, inventory systems) to reinforce concepts.

1. Problem-Solving Methodology in C

Step-by-Step Approach

Every problem requires a structured approach. Here’s how to break it down:

  1. Understand the Problem

    • Read carefully. Identify inputs, outputs, and constraints.
    • Example: "Design a program to calculate the total bill for a restaurant, including a 13% VAT and a 10% service charge if the bill exceeds Rs. 1000."
  2. Plan the Algorithm

    • Use pseudocode or flowcharts to outline steps.
    • Example pseudocode for the restaurant bill:
      1. Input: bill_amount
      2. If bill_amount > 1000:
         service_charge = 10% of bill_amount
      3. vat = 13% of (bill_amount + service_charge)
      4. total = bill_amount + service_charge + vat
      5. Output: total
      
  3. Design the Program Structure

    • Decide on functions, loops, and data structures.
    • Example: Use a function calculate_total() to encapsulate the logic.
  4. Write the Code

    • Translate pseudocode into C, ensuring correctness.
  5. Test and Debug

    • Test with edge cases (e.g., bill = Rs. 0, Rs. 1000, Rs. 2000).
    • Debug using printf() for intermediate values.

Worked Example: Restaurant Bill Calculator

Code Implementation

#include <stdio.h>

float calculate_total(float bill_amount) {
    float service_charge = 0, vat, total;
    if (bill_amount > 1000) {
        service_charge = 0.10 * bill_amount;
    }
    vat = 0.13 * (bill_amount + service_charge);
    total = bill_amount + service_charge + vat;
    return total;
}

int main() {
    float bill;
    printf("Enter bill amount: ");
    scanf("%f", &bill);
    printf("Total bill: Rs. %.2f\n", calculate_total(bill));
    return 0;
}

Trace Table for calculate_total(1500)

Step service_charge vat total
1. Input: 1500 0 0 0
2. if condition 150 (10% of 1500) 0 0
3. Calculate VAT 150 239 (13% of 1750) 0
4. Calculate total 150 239 1889 (1500+150+239)

2. Debugging and Testing

Common Types of Errors

Error Type Description Example How to Fix
Syntax Error Violates C grammar rules. Missing ; or } Compiler flags the line.
Logical Error Program runs but gives wrong output. Incorrect formula in calculate_total() Test with known inputs.
Runtime Error Crashes during execution. Division by zero. Add checks (e.g., if (denominator != 0)).

Debugging Techniques

  1. Print Debugging Add printf() statements to track variable values. Example:

    printf("Bill: %.2f, Service: %.2f\n", bill_amount, service_charge);
    
  2. Use a Debugger (GDB)

    • Set breakpoints to pause execution.
    • Step through code line by line.
  3. Unit Testing Test individual functions with known inputs/outputs. Example for calculate_total():

    Input (bill_amount) Expected Output Actual Output Pass/Fail
    500 565 565 Pass
    1000 1130 1130 Pass
    2000 2466 2466 Pass

3. Practical Applications

In the Real World

  1. eSewa (Nepal)

    • Idea Used: File Handling and Dynamic Memory
    • How? eSewa stores transaction records in files (e.g., transactions.dat). When a user pays a bill, the program:
      • Reads the existing file.
      • Dynamically allocates memory for a new transaction struct.
      • Appends the transaction to the file.
      • Frees memory to avoid leaks.
  2. Khalti (Nepal)

    • Idea Used: Modular Programming (Functions) and Debugging
    • How? Khalti’s backend uses functions to:
      • Validate user input (e.g., is_valid_amount()).
      • Process payments (process_payment()).
      • Log errors (e.g., insufficient balance) for debugging.
  3. Bank Loan Calculations

    • Idea Used: Loops and Algorithms
    • How? A bank calculates monthly EMI (Equated Monthly Installment) using the formula: where:
      • = Principal loan amount,
      • = Monthly interest rate,
      • = Number of payments.
    • C Implementation:
      #include <stdio.h>
      #include <math.h>
      
      float calculate_emi(float principal, float annual_rate, int years) {
          float r = annual_rate / 12 / 100; // Monthly rate
          int n = years * 12;               // Total payments
          return principal * r * pow(1 + r, n) / (pow(1 + r, n) - 1);
      }
      
      int main() {
          printf("EMI for Rs. 5,00,000 at 8%% for 5 years: Rs. %.2f\n",
                 calculate_emi(500000, 8, 5));
          return 0;
      }
      
    • Trace for calculate_emi(500000, 8, 5):
      Variable Value
      r 0.0066667 (8%/12)
      n 60 (5 years * 12)
      pow(1 + r, n) ~1.4859 (approx.)
      EMI ~9,802.65

4. File Handling in Practical Scenarios

Example: Student Gradebook

Problem: Store student grades in a file and calculate the average.

850921782903884
Array storing grades (index 2 = 78, used for average calculation)
850921782903884
Array storing student grades (index 2 = 78, highlighted for average calculation).

Steps:

  1. Create a File Use fopen() to create/write to grades.txt.
  2. Write Data Append grades dynamically.
  3. Read and Calculate Average Read all grades, sum them, and compute the average.
534264ThamelKageshworiKirtipurBalkhuNaxalTIA
Complete graph with shortest path to TIA (total 15 km)

Code

#include <stdio.h>

int main() {
    FILE *file = fopen("grades.txt", "a+");
    if (file == NULL) {
        printf("Error opening file!\n");
        return 1;
    }

    // Write grades (example)
    fprintf(file, "85\n72\n90\n");

    // Reset file pointer to start
    rewind(file);

    // Read and calculate average
    int grade, sum = 0, count = 0;
    while (fscanf(file, "%d", &grade) != EOF) {
        sum += grade;
        count++;
    }
    printf("Average grade: %.2f\n", (float)sum / count);

    fclose(file);
    return 0;
}

File State After Execution

grades.txt:
85
72
90

Output:

Average grade: 82.33

5. Dynamic Memory Management

Example: Inventory System for Daraz

Problem: Store product names and quantities dynamically (no fixed size).

LoadAdd new itemUpdate stockSaveSaveDatabaseInventoryNew ItemUpdated ItemEnd
Dynamic inventory system workflow (Daraz example).

Approach:

  1. Use struct to represent a product.
  2. Dynamically allocate an array of products.
  3. Free memory when done.

Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Product {
    char name[50];
    int quantity;
};

int main() {
    int n;
    printf("Enter number of products: ");
    scanf("%d", &n);

    // Dynamically allocate memory
    struct Product *inventory = (struct Product*)malloc(n * sizeof(struct Product));
    if (inventory == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }

    // Input products
    for (int i = 0; i < n; i++) {
        printf("Enter product %d name and quantity: ", i + 1);
        scanf("%s %d", inventory[i].name, &inventory[i].quantity);
    }

    // Display inventory
    printf("\nInventory:\n");
    for (int i = 0; i < n; i++) {
        printf("%s: %d\n", inventory[i].name, inventory[i].quantity);
    }

    // Free memory
    free(inventory);
    return 0;
}

Memory State After Allocation

inventory (pointer) --> [Product 1] --> [Product 2] --> ... --> [Product n]

Example Output:

Enter number of products: 2
Enter product 1 name and quantity: Laptop 10
Enter product 2 name and quantity: Phone 25

Inventory:
Laptop: 10
Phone: 25

6. Modular Programming with Header Files

Example: Library Management System

Problem: Separate functions into header files for reusability.

Structure:

  1. library.h (Header File)

    #ifndef LIBRARY_H
    #define LIBRARY_H
    
    void add_book(char title[], int id);
    void display_books();
    
    #endif
    
  2. library.c (Implementation)

    #include <stdio.h>
    #include "library.h"
    
    void add_book(char title[], int id) {
        FILE *file = fopen("books.txt", "a");
        fprintf(file, "%s,%d\n", title, id);
        fclose(file);
    }
    
    void display_books() {
        FILE *file = fopen("books.txt", "r");
        char line[100];
        while (fgets(line, sizeof(line), file)) {
            printf("%s", line);
        }
        fclose(file);
    }
    
  3. main.c (Usage)

    #include <stdio.h>
    #include "library.h"
    
    int main() {
        add_book("C Programming", 101);
        display_books();
        return 0;
    }
    

Compilation Command

gcc main.c library.c -o library

Output File (books.txt)

C Programming,101

7. Algorithmic Problem Solving

Example: Shortest Path in Kathmandu Traffic

Problem: Find the shortest path from Thamel to Tribhuvan International Airport (TIA) using Dijkstra’s algorithm.

53426ThamelKageshworiKirtipurBalkhuNaxal
Shortest path from Thamel to Naxal (total distance: 11 km).

Graph Representation (Adjacency Matrix)

Dijkstra’s Algorithm Steps

  1. Initialize distances: Thamel = 0, others = ∞.
  2. Update neighbors:
    • Thamel → Kageshwori: 5 km
    • Thamel → Kantipath: 8 km
  3. Select Kageshwori (smallest distance).
  4. Update TIA via Kageshwori: 5 + 3 = 8 km.
  5. Select Kantipath (next smallest).
  6. Update TIA via Kantipath: min(8, 8 + 6) = 8 km.
  7. Shortest path: Thamel → Kageshwori → TIA (8 km).

C Implementation

#include <stdio.h>
#include <limits.h>

#define V 4 // Vertices: Thamel(0), Kageshwori(1), Kantipath(2), TIA(3)

void dijkstra(int graph[V][V], int src) {
    int dist[V];
    for (int i = 0; i < V; i++) dist[i] = INT_MAX;
    dist[src] = 0;

    for (int count = 0; count < V - 1; count++) {
        int u = -1, min = INT_MAX;
        for (int v = 0; v < V; v++) {
            if (dist[v] < min && dist[v] != INT_MAX) {
                min = dist[v];
                u = v;
            }
        }
        if (u == -1) break;

        for (int v = 0; v < V; v++) {
            if (graph[u][v] && dist[u] != INT_MAX &&
                dist[u] + graph[u][v] < dist[v]) {
                dist[v] = dist[u] + graph[u][v];
            }
        }
    }

    printf("Shortest distances from Thamel:\n");
    for (int i = 0; i < V; i++) {
        printf("%d: %d km\n", i, dist[i]);
    }
}

int main() {
    int graph[V][V] = {
        {0, 5, 8, 0},
        {0, 0, 0, 3},
        {0, 0, 0, 6},
        {0, 0, 0, 0}
    };
    dijkstra(graph, 0);
    return 0;
}

Output

Shortest distances from Thamel:
0: 0 km
1: 5 km
2: 8 km
3: 8 km

Exam Tip

What to Expect in TU/PU Exams

  1. Problem-Solving Questions (40-50%)

    • Expect 2-3 problems requiring:
      • File handling (read/write operations).
      • Dynamic memory allocation (e.g., linked lists).
      • Modular design (header files, functions).
    • Tip: Always plan your algorithm on paper before coding.
  2. Debugging (20%)

    • Given a buggy code snippet, identify and fix errors.
    • Example:
      // Buggy code (missing return type in function)
      void add(int a, int b) {
          return a + b; // Error: void function cannot return value
      }
      
    • Fix: Change to int add(int a, int b).
  3. Short Answer (20%)

    • Define terms like:
      • Modularity: Breaking a program into independent modules (functions/header files).
      • Dynamic Memory: Memory allocated at runtime using malloc(), calloc().
    • Tip: Use real-world analogies (e.g., "Dynamic memory is like renting a hotel room for your data temporarily").
  4. Practical Implementation (20%)

    • Write a complete program for scenarios like:
      • Student record management (structures + file handling).
      • Simple calculator (functions + user input).
    • Tip: Start with main(), then define helper functions.

Common Pitfalls to Avoid

  • Memory Leaks: Always free() dynamically allocated memory.
    int *arr = malloc(10 * sizeof(int));
    // ... use arr ...
    free(arr); // Critical!
    
  • Buffer Overflows: Use fgets() instead of gets() for strings.
  • Incorrect File Modes: Use "r" for reading, "w" for writing (overwrites), "a" for appending.
  • Floating-Point Precision: Use %.2f in printf() for 2 decimal places.

Final Checklist Before Submission

  1. Code Structure:
    • Proper indentation and comments.
    • Logical function separation.
  2. Testing:
    • Test with edge cases (empty input, maximum values).
  3. Memory Management:
    • No leaks; all malloc() has free().
  4. File Handling:
    • Check if fopen() succeeded (if (file == NULL)).
  5. Output Formatting:
    • Use \n for newlines, %.2f for floats.

restaurant bill receipt**A sample bill showing subtotal, VAT, and total. (Image: Peter Merholz from Berkeley, CA, United States, CC BY-SA 2.0, via Wikimedia Commons)

In the real world

  • eSewa: Uses file handling to store transaction records (e.g., transactions_2081.dat) and dynamic memory to process payments in real-time, ensuring no data loss during high traffic.
  • Daraz Inventory System: Employs linked lists to manage product stock dynamically, allowing quick updates and searches without loading the entire database into memory.
  • Nepal Telecom (NTC) Billing: Applies hash tables to map customer IDs to billing records for O(1) access time, improving efficiency in generating monthly bills for millions of users.

Based on the PU BE Computer (PU) syllabus for Programming In C, unit 14.

Discussion

Loading…