C ProgrammingUnit 612 min read
Functions in C: Definition, Types, Scope, Recursion & Practical Use
Unit 6 of C Programming covers functions—how to define, call, and use them in programs, including parameter passing, scope rules, recursion, and real-world applications like transaction processing in eSewa or order routing in Daraz.
TAKEAWAYS:
- Functions modularize code by breaking programs into reusable blocks with a single responsibility (e.g.,
calculateTax()). - Passing arguments by value vs. by reference changes how functions modify data (e.g.,
swap()needs pointers). - Scope rules (local vs. global) determine variable lifetime and accessibility (e.g.,
staticvariables retain values between calls). - Recursion solves problems like tree traversals or factorial calculations but risks stack overflow if not optimized.
- Header files (
#include) and function prototypes (int add(int, int);) enable code organization and compilation. - Memory efficiency: Functions reduce redundancy (e.g.,
validateUser()reused across login/logout).
1. What is a Function?
A function is a self-contained block of code that performs a specific task. It:
- Takes inputs (parameters/arguments).
- Executes statements.
- Returns an output (optional).
Why use functions?
- Reusability: Write once, call anywhere (e.g.,
login()in eSewa). - Modularity: Divide programs into manageable parts (e.g.,
processOrder()in Daraz). - Debugging: Isolate errors to a single function.
flowchart TD
A["Main Program"] -->|"Calls"| B["Function: calculateTax(income)"]
B -->|"Returns"| C["taxAmount"]
A -->|"Uses"| C2. Function Syntax and Components
A function has 5 key parts:
- Return type: Data type of the result (
int,void, etc.). - Function name: Identifier (e.g.,
calculateTax). - Parameters: Inputs in parentheses (e.g.,
(float income)). - Body: Code block
{ ... }. - Return statement:
return value;.
Example: Simple Function
// Function prototype (declaration)
float calculateTax(float income);
// Function definition
float calculateTax(float income) {
float tax;
if (income > 500000) {
tax = income * 0.15; // 15% tax for high income
} else {
tax = income * 0.10; // 10% tax for low income
}
return tax;
}
Real-World Link:
In eSewa, the processPayment() function takes userID and amount as parameters, validates them, deducts the tax using calculateTax(), and returns a transaction ID. This mirrors the example above but with additional security checks.
3. Types of Functions
| Type | Description | Example |
|---|---|---|
| Library Functions | Predefined in C standard libraries (e.g., printf(), strlen()). |
sqrt(25) |
| User-Defined | Created by the programmer for specific tasks. | validateUser(username, password) |
| Recursive | A function calls itself (e.g., factorial, Fibonacci). | factorial(n) |
| Void Functions | Perform tasks but do not return a value. | displayWelcomeMessage() |
4. Passing Arguments: Call by Value vs. Call by Reference
| Method | How It Works | Example | Use Case |
|---|---|---|---|
| Call by Value | A copy of the argument is passed. Changes inside the function are lost. | void increment(int x) |
Safe for read-only operations. |
| Call by Reference | The memory address of the argument is passed. Changes affect the original. | void swap(int *a, int *b) |
Modifying arrays or large data. |
Example: Swapping Two Numbers (Call by Reference)
#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
swap(&x, &y); // Pass addresses
printf("x = %d, y = %d", x, y); // Output: x = 10, y = 5
return 0;
}
Visual Trace:
flowchart LR
A["Before swap(x=5, y=10)"] --> B["swap(&x, &y)"]
B --> C["temp = *a (5)"]
B --> D["*a = *b (10)"]
B --> E["*b = temp (5)"]
E --> F["After swap(x=10, y=5)"]Real-World Link:
In Pathao’s ride-matching system, the assignDriver() function uses call by reference to update the driverLocation and passengerLocation arrays directly, ensuring real-time GPS updates without copying large data.
5. Scope of Variables
Variables can be:
- Local: Exist only within the function.
- Global: Accessible throughout the program (use sparingly!).
- Static: Retain value between function calls.
| Scope | Lifetime | Accessibility | Example |
|---|---|---|---|
| Local | Function call | Only within the function. | int sum = 0; in calculateSum() |
| Global | Entire program | Anywhere in the program. | int totalUsers; at file scope. |
| Static | Program duration | Only within the function. | static int count = 0; |
Example: Static Variable
#include <stdio.h>
void counter() {
static int count = 0; // Retains value between calls
count++;
printf("Count: %d\n", count);
}
int main() {
counter(); // Output: 1
counter(); // Output: 2
return 0;
}
Visual Trace:
Real-World Link:
Ncell’s call counter uses a static variable to track the number of failed login attempts per user. This persists across multiple login() calls without resetting.
6. Recursion
A function that calls itself to solve smaller instances of the same problem.
Base Case: Stops the recursion (e.g., factorial(0) = 1).
Recursive Case: Breaks the problem into smaller subproblems.
Example: Factorial
#include <stdio.h>
int factorial(int n) {
if (n == 0) // Base case
return 1;
else
return n * factorial(n - 1); // Recursive call
}
int main() {
printf("Factorial of 5: %d", factorial(5)); // Output: 120
return 0;
}
Visual Trace (Stack Frames):
Real-World Link: NEPSE’s stock price prediction uses recursive algorithms to analyze historical data patterns. For example, calculating the n-th Fibonacci number (common in technical analysis) is done recursively:
int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
Warning: Recursion can cause stack overflow for large n (e.g., fibonacci(1000)). Use iteration or memoization for optimization.
7. Function Prototypes and Header Files
Function Prototype: Declares a function before its definition (helps compilation).
// Prototype (in header file or before main)
int add(int a, int b);
```figure
{"type":"tree","root":{"v":"main.c","children":[{"v":"header.h","children":[{"v":"function_prototype()"},{"v":"constant_definitions"}]},{"v":"main()","children":[{"v":"include header.h"},{"v":"function_call()"},{"v":"printf()"}]}]},"caption":"File structure for prototypes and header usage"}
// Definition (later in the code) int add(int a, int b) { return a + b; }
Header Files: Store prototypes and constants (e.g., #include "math_utils.h").
Example:
// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
int add(int, int);
float divide(float, float);
#endif
Real-World Link: Daraz’s order processing system uses header files to separate:
order.h: Prototypes forplaceOrder(),cancelOrder().order.c: Definitions of these functions.main.c: Calls these functions without needing to see their implementations.
8. Advantages and Disadvantages of Functions
| Advantages | Disadvantages |
|---|---|
Code reusability (e.g., login() in multiple apps). |
Overhead: Function calls add slight performance cost. |
| Modularity: Easier to debug/test. | Complexity: Recursion can be hard to follow. |
Security: Limit access to critical functions (e.g., adminOnly()). |
Scope issues: Misusing globals can cause bugs. |
| Teamwork: Different programmers can work on separate functions. | Memory: Deep recursion may cause stack overflow. |
9. Common Pitfalls and Best Practices
- Uninitialized Variables: Always initialize local variables (e.g.,
int sum = 0;). - Incorrect Return Types: Ensure
voidfunctions don’t return values. - Passing Wrong Arguments: Mismatched types (e.g., passing
floattointfunction). - Infinite Recursion: Forgetting the base case (e.g.,
factorial(-1)). - Global Variable Overuse: Prefer local/static variables to avoid side effects.
Best Practices:
- Use descriptive names (e.g.,
calculateVAT()instead ofcalc()). - Limit function size to ~20-30 lines for readability.
- Comment prototypes to explain parameters and return values.
In the Real World
eSewa’s Transaction System:
- Idea Used: Modular functions (
validateUser(),deductAmount(),generateReceipt()). - How: Each function handles a specific step (e.g.,
deductAmount()takesuserIDandamount, checks balance, and returns success/failure). Call by reference ensures the user’s balance is updated directly.
- Idea Used: Modular functions (
Pathao’s Driver-Passenger Matching:
- Idea Used: Recursion + Call by Reference.
- How: The
findNearestDriver()function recursively checks drivers within a radius, updating thedriverLocationarray via pointers. This avoids copying large GPS data.
Ncell’s Billing System:
- Idea Used: Static variables + Functions.
- How: The
checkSMSLimit()function uses astatic int usedSMS;to track usage across calls, ensuring accurate billing without resetting between function invocations.
Daraz’s Order Queue:
- Idea Used: Function prototypes + Header files.
- How:
order.hdeclaresprocessOrder(),cancelOrder(), andupdateInventory(), whileorder.cdefines them. This separation lets the team update order logic without breaking the main program.
Exam Tip
Function Definition vs. Prototype:
- Definition: Includes the body (e.g.,
int add(int a, int b) { return a + b; }). - Prototype: Only declares (e.g.,
int add(int, int);). - Exam Trick: If asked to "write a function," provide the full definition. If asked to "declare," give the prototype.
- Definition: Includes the body (e.g.,
Tracing Recursion:
- Always show the stack frames (like the
factorialexample above). Examiners love step-by-step traces. - Common Mistake: Forgetting the base case. Always include it in your answer.
- Always show the stack frames (like the
Call by Value vs. Reference:
- Value: Changes inside the function are lost (e.g.,
swap(int a, int b)won’t work). - Reference: Use pointers (
swap(int *a, int *b)) to modify original data. - Exam Question: "Why does this code not swap
xandy?" → Answer: Call by value (no pointers).
- Value: Changes inside the function are lost (e.g.,
Static Variables:
- Key Point: Retain value between calls but are local to the function.
- Exam Question: "What will this program print?" (with a
staticcounter) → Trace the retained value.
Header Files:
- Why Use Them?: To avoid redefining functions and for code organization.
- Exam Tip: If asked to "organize this code," split functions into
.hand.cfiles.
Real-World Scenarios:
- Bank Loan Interest: Write a function
calculateEMI(float principal, float rate, int years)and trace it for a loan of ₹5,00,000 at 8% for 5 years. - Traffic Light Control: Use a
void changeLight()function withstatic int currentLightto cycle through red/green/yellow.
- Bank Loan Interest: Write a function
Pro Tip: For practical exams, always draw the stack frames for recursive functions and show variable changes in tables for call-by-reference examples. This visual approach guarantees full marks.
Based on the TU BIM syllabus for C Programming (IT232), unit 6.
Discussion
Loading…