C ProgrammingUnit 69 min read
Functions in C: Definitions, Types, Passing Arguments & Recursion
Unit 6 of C Programming covers function definitions, types (library vs user-defined), argument passing (call-by-value/reference), recursion, and practical applications with DMA. Learn with visual traces, real-world examples, and exam-focused problem-solving.
TAKEAWAYS:
- Functions are reusable code blocks that modularize programs, improving readability and reusability.
- Call-by-value passes a copy of the argument (safe but no changes reflect outside), while call-by-reference passes memory addresses (modifies original data).
- Recursion solves problems by breaking them into smaller subproblems (e.g., Fibonacci series, tree traversals).
- Dynamic Memory Allocation (DMA) (
malloc,calloc,realloc,free) manages memory at runtime for flexible data structures like arrays. - Library functions (e.g.,
printf,sqrt) are pre-defined, while user-defined functions are custom-written for specific tasks. - Exam focus: Trace function calls, debug argument passing, and write recursive solutions with base cases.
1. What is a Function?
A function is a self-contained block of code that performs a specific task. It:
- Encapsulates logic (e.g., calculating factorial, validating input).
- Reuses code (avoids repetition).
- Improves modularity (easier debugging/maintenance).
Syntax
return_type function_name(parameter_list) {
// Function body
return value; // Optional for void functions
}
Example: A function to add two numbers.
#include <stdio.h>
int add(int a, int b) { // User-defined function
return a + b;
}
int main() {
int x = 5, y = 7;
printf("Sum: %d", add(x, y)); // Output: 12
return 0;
}
2. Types of Functions
A. Library Functions
Pre-defined in C standard libraries (e.g., math.h, stdio.h).
Example: sqrt() from math.h.
#include <math.h>
#include <stdio.h>
int main() {
double num = 25.0;
printf("Square root: %f", sqrt(num)); // Output: 5.000000
return 0;
}
B. User-Defined Functions
Written by the programmer for custom tasks. Example: Calculate area of a circle.
float area(float radius) {
return 3.14 * radius * radius;
}
3. Passing Arguments to Functions
A. Call-by-Value
- Copies the argument’s value to the function.
- Original data remains unchanged outside the function.
- Use case: When you don’t need to modify the original data.
Example: Swap two numbers (ineffective due to call-by-value).
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 5, y = 10;
swap(x, y); // x and y remain 5 and 10
printf("x: %d, y: %d", x, y); // Output: 5, 10
}
B. Call-by-Reference
- Passes memory address of the argument.
- Modifies original data directly.
- Use case: Dynamic memory allocation, large data structures.
Example: Effective swap using pointers.
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
swap(&x, &y); // x and y are swapped
printf("x: %d, y: %d", x, y); // Output: 10, 5
}
Comparison Table
| Feature | Call-by-Value | Call-by-Reference |
|---|---|---|
| Data Passed | Copy of value | Memory address |
| Original Data | Unchanged | Modified |
| Syntax | function(arg) |
function(&arg) |
| Use Case | Read-only operations | Modifying original data |
| Memory Overhead | Higher (copies data) | Lower (passes address) |
4. Recursion in C
Recursion is a function calling itself to solve smaller instances of the same problem. Key Components:
- Base Case: Terminates recursion (e.g.,
factorial(0) = 1). - Recursive Case: Breaks problem into smaller subproblems.
Example: Factorial Using Recursion
int factorial(int n) {
if (n == 0) // Base case
return 1;
else
return n * factorial(n - 1); // Recursive call
}
int main() {
int num = 5;
printf("Factorial: %d", factorial(num)); // Output: 120
return 0;
}
Trace of factorial(3)
| Call Stack | Return Value |
|---|---|
factorial(3) |
3 * factorial(2) |
factorial(2) |
2 * factorial(1) |
factorial(1) |
1 * factorial(0) |
factorial(0) |
1 (base case) |
| Unwinding | 1 * 1 = 1 → 2 * 1 = 2 → 3 * 2 = 6 |
5. Dynamic Memory Allocation (DMA)
Static memory (e.g., arrays) has fixed size. DMA allocates memory at runtime using:
malloc(): Allocates memory (uninitialized).calloc(): Allocates and initializes to zero.realloc(): Resizes previously allocated memory.free(): Releases allocated memory.
Example: Sum of N Numbers Using DMA
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, i, sum = 0;
printf("Enter N: ");
scanf("%d", &n);
int *arr = (int*)malloc(n * sizeof(int)); // Allocate memory
printf("Enter %d numbers: ", n);
for (i = 0; i < n; i++)
scanf("%d", &arr[i]);
for (i = 0; i < n; i++)
sum += arr[i];
printf("Sum: %d", sum);
free(arr); // Release memory
return 0;
}
Memory Allocation Steps
flowchart TD
A["Start"] --> B["Input N"]
B --> C["Allocate memory: arr = malloc(N * sizeof(int))"]
C --> D["Input N numbers into arr"]
D --> E["Calculate sum"]
E --> F["Print sum"]
F --> G["Free memory: free(arr)"]
G --> H["End"]6. Real-World Applications
A. eSewa (Nepal)
- Function Use: Modular functions for payment processing, user authentication, and transaction logging.
- DMA: Dynamically allocates memory for handling variable-sized transaction records.
B. Pathao (Ride-Hailing App)
- Recursion: Used in pathfinding algorithms (e.g., calculating shortest routes via recursive tree traversal).
- Call-by-Reference: Updates ride status (e.g., "accepted," "cancelled") in real-time.
C. Bank Loan Interest Calculation
Problem: Calculate monthly interest for a loan of ₹1,000,000 at 8% annual rate for 5 years. Solution: Use a recursive function to compute compound interest.
float calculateInterest(float principal, float rate, int years) {
if (years == 0)
return principal;
else
return calculateInterest(principal * (1 + rate/100), rate, years - 1);
}
int main() {
float principal = 1000000;
float rate = 8.0;
int years = 5;
printf("Amount after %d years: %.2f", years, calculateInterest(principal, rate, years));
return 0;
}
Output: ₹1,469,328.07
7. Common Pitfalls & Debugging
- Infinite Recursion: Forgetting the base case.
int infinite() { infinite(); // Stack overflow! } - Memory Leaks: Forgetting to
free()allocated memory.int *ptr = malloc(sizeof(int)); // ptr is never freed! - Incorrect Argument Passing: Mixing call-by-value/reference.
void incorrect(int x) { x = 10; } // Won’t modify original
8. Exam Tips
Function Definition:
- Always declare return type and parameters.
- Use meaningful names (e.g.,
calculateArea()instead offunc1()).
Argument Passing:
- Call-by-value: Original data is not modified.
- Call-by-reference: Use pointers (
&) to modify original data. - Exam trick: If a function modifies input, it must use pointers.
Recursion:
- Always include a base case to terminate recursion.
- Trace the call stack (like the
factorialexample above). - Common patterns:
- Fibonacci series.
- Tower of Hanoi.
- Tree traversals (in-unit 7).
DMA:
- Check for
NULLaftermalloc/callocto avoid crashes. - Free memory at the end to prevent leaks.
- Example question: "Write a program to store student marks using DMA and find the average."
- Check for
Code Structure:
- Declare functions before
main()or use prototypes. - Example:
int add(int, int); // Prototype int main() { ... } int add(int a, int b) { ... } // Definition
- Declare functions before
9. Practice Problems
- Write a function to check if a number is prime.
- Use recursion to print the Fibonacci series up to the 10th term.
- DMA: Create an array of 10 integers dynamically and sort it in ascending order.
- Call-by-reference: Write a function to reverse a string (pass the string as a pointer).
- Real-world: Simulate a bank ATM with functions for
deposit(),withdraw(), andcheckBalance().
10. Summary Visual: Function Call Flow
sequenceDiagram
participant Main as main()
participant Add as add(a, b)
Main->>Add: Calls add(5, 7)
Add-->>Main: Returns 12
Main->>Print: Displays resultBased on the TU BCA syllabus for C Programming (CACS151), unit 6.
Discussion
Loading…