CASE STUDY 03 · C PROGRAMMING

Intermediate Decision logic

Electricity Billing System

Translate meter readings and progressive tariff rules into a transparent bill while protecting every important input and slab boundary.

01 · PROBLEM DEFINITION

A bill must be correct and explainable

An electricity bill begins with two cumulative meter readings. Their difference is the consumption for the billing period. The difficult part is not subtraction; it is applying each tariff rate only to the units that belong to its slab, validating impossible readings and presenting each component clearly enough for a consumer to verify.

Measure

Units consumed = current reading − previous reading.

Price

Split consumption across progressive tariff slabs.

Explain

Show energy, fixed, surcharge and final amounts separately.

Scope: This learning system prepares one bill per run. The tariff values are fictional examples, not rates from an electricity provider.
02 · REQUIREMENTS & RULES

Turn policy statements into testable conditions

RequirementRuleFailure response
Consumer identityNumber and name must not be emptyAsk again
Meter readingsBoth readings are non-negative whole numbersReject invalid input
Reading sequenceCurrent reading ≥ previous readingStop without producing a bill
Consumptionunits = current − previousNever accept units independently
Energy chargeCharge each block at its own rateProtect exact slab boundaries
Surcharge5% only when energy charge > ₹1,500No surcharge at exact equality
Core invariant: A successfully prepared bill always has non-negative units and a total equal to energy charge + fixed charge + surcharge.
03 · DATA MODEL

Separate tariff policy from bill data

TariffSlab

upperLimit marks the cumulative end of a slab; rate stores its price per unit. A negative upper limit represents the unlimited final slab.

ElectricityBill

Stores consumer identity, readings, derived units and every monetary component. One structure can be passed safely between calculation and display functions.

Input fields → validated readings → derived units → energy charge
                                            ↓
                                     fixed + surcharge
                                            ↓
                                      payable total

Why keep derived values?

Saving the energy charge, surcharge and total inside the bill makes the printed result auditable. In a larger system, these values would also form a billing snapshot: later tariff changes would not silently rewrite an already issued bill.

04 · PROGRESSIVE TARIFF LOGIC

Charge blocks—not all units at the last rate

Consumption blockUnits available in blockExample rate
0–100100₹1.50
101–200100₹2.50
201–500300₹4.00
Above 500Unlimited₹6.00

Worked example: 650 units

  1. First 100: 100 × ₹1.50 = ₹150.
  2. Next 100: 100 × ₹2.50 = ₹250.
  3. Next 300: 300 × ₹4.00 = ₹1,200.
  4. Remaining 150: 150 × ₹6.00 = ₹900.
  5. Energy charge = ₹2,500; surcharge = 5% = ₹125.
  6. Total = ₹2,500 + ₹75 fixed charge + ₹125 = ₹2,700.
Common bug: Multiplying all 650 units by ₹6 gives ₹3,900. That is a single-rate calculation and ignores the progressive slabs.
05 · FUNCTIONAL DESIGN

Give each function one reason to change

Read identity
Validate readings
Calculate slabs
Prepare totals
Print bill
FunctionResponsibilityImportant guarantee
readNonEmptyLineRead bounded text using fgetsNo empty identity
readNonNegativeIntRead and validate a meter valueValue ≥ 0
calculateEnergyChargeWalk tariff slabsEach unit priced once
prepareBillDerive every computed fieldReject reversed readings
printBillFormat the final breakdownNo calculation mixed with UI

Tariffs are stored in an array rather than a long if/else chain. Adding or changing a slab is therefore mainly a data change, while the calculation loop remains stable.

06 · COMPLETE IMPLEMENTATION

Compiler-ready C11 program

The program accepts a consumer number, a name and two meter readings. It performs bounded text input, rejects invalid numbers, calculates a progressive charge and prints a complete breakdown.

programs/electricity-billing-system.c
Open Compiler
Loading source…
Adaptation rule: Before using this for a real provider, replace the sample tariff, fixed charge, surcharge policy, currency formatting, taxes and rounding rules with verified official requirements.
07 · INTERACTIVE PROGRAM TRACING

Trace: readings 4,250 and 4,900

  1. The meter readings pass basic validation.
  2. prepareBill accepts the reading order.
  3. Consumption is derived, not typed separately.
  4. Calculate the first block.
  5. Calculate the second block.
  6. Calculate the third block.
  7. Price the units above 500.
  8. Apply the threshold rule.
  9. Add energy, fixed charge and surcharge.
  10. Display an auditable result.
Current state

Press Next to begin.

08 · BOUNDARY-FIRST TESTING

Test immediately before and after every slab boundary

UnitsExpected energy chargeWhy it matters
0₹0.00Zero-consumption case
100₹150.00End of slab 1
101₹152.50First unit in slab 2
200₹400.00End of slab 2
201₹404.00First unit in slab 3
500₹1,600.00End of slab 3; surcharge applies
501₹1,606.00First unit in final slab
650₹2,500.00Uses all four slabs
Invalid reading order
Previous = 900 and current = 875. Expected: error message, non-zero exit status and no bill.
Invalid numeric input
Enter letters or a negative reading. Expected: the program clears the line and asks again rather than using an uninitialised value.
Surcharge boundary
Test energy charges just below, exactly at and just above ₹1,500. The rule uses >, so equality must not add a surcharge.
09 · COMPLEXITY & NUMERIC TRADE-OFFS

The algorithm scales with the number of slabs

OperationTimeExtra spaceReason
Validate readingsO(1)O(1)Constant comparisons
Calculate energy chargeO(s)O(1)Visits at most s tariff slabs
Prepare billO(s)O(1)Calculation dominates
Print billO(1)O(1)Fixed number of fields

Here s = 4, so runtime is effectively constant. The sample uses double for readability. Financial production software often stores the smallest currency unit as an integer or uses a decimal type so binary floating-point rounding cannot accumulate unnoticed.

10 · PRACTICE & EXTENSIONS

Check your reasoning, then extend the system

For 201 units, how many units are charged at ₹4.00?

Which invariant protects the consumption calculation?

Build the next version

  1. Print a slab-by-slab charge breakdown on the receipt.
  2. Add domestic and commercial tariff plans without duplicating the calculation loop.
  3. Store many consumers in a file and search by consumer number.
  4. Add billing dates, due dates and a clearly specified late-fee rule.
  5. Create automated tests for every slab and surcharge boundary.
11 · INTERVIEW PREPARATION

Questions your project should answer

Why use an array of tariff slabs?

It separates policy data from control flow. The calculation loop can process any ordered set of slabs, which reduces repeated conditions and makes tariff changes easier to review.

Why derive units from readings?

Both readings are observable meter states. Accepting a separately typed consumption value creates two sources of truth that could disagree.

What is the most likely boundary bug?

Charging the 100th or 200th unit twice, or moving it into the next slab too early. Tests at boundary−1, boundary and boundary+1 expose the error.

Why not use float for money?

Float has lower precision. Double is better for this educational example, but production billing should follow a defined decimal or integer-smallest-unit policy with explicit rounding.

How would you make issued bills reproducible?

Store the exact tariff version and computed line items with each bill. Recalculating an old bill using today's tariff could produce a different result.

12 · KEY TAKEAWAY

Correct software makes policy visible

This project connects structures, arrays, functions, input validation, loops and formatted output to a real decision process. Its strongest lesson is that business rules must become explicit invariants and boundary tests—not assumptions hidden inside arithmetic.