Elective Programming In C

Programming In CUnit 712 min read

Functions in C: Definitions, Types, Recursion, Pointers & Applications

Unit 7 of Programming In C covers function definitions, types (predefined vs user-defined), function calls, recursion, passing arguments (by value/address), scope rules, and practical applications like array processing and Fibonacci series generation—with visual traces, real-world examples, and exam-focused problem-sol

TAKEAWAYS:

  • Functions modularize code by breaking programs into reusable blocks with a single responsibility (e.g., calculate_area() for circles/squares).
  • Passing arguments by value copies data (safe but inefficient for large data), while passing by address (pointers) modifies original data (faster but risky).
  • Recursion solves problems by breaking them into smaller subproblems (e.g., Fibonacci, factorial), but risks stack overflow if not optimized.
  • Scope rules limit variable visibility: local (block-level), global (file-level), and static (persists across calls).
  • Header files (e.g., #include <stdio.h>) provide prewritten function libraries (I/O, math) to avoid rewriting code.
  • Exam focus: Expect programming questions (e.g., "write a function to sort an array") and theory questions (e.g., "advantages of recursion").

1. What Are Functions?

Functions are self-contained blocks of code that perform a specific task. They:

  • Reduce code duplication (DRY principle: Don’t Repeat Yourself).
  • Improve readability by giving names to operations (e.g., login_user()).
  • Enhance reusability (call the same function from multiple places).

Types of Functions in C

Type Description Example
Predefined Built-in functions (e.g., printf(), sqrt()) from header files. #include <math.h> → sqrt(9)
User-defined Created by the programmer using return_type function_name(parameters). int add(int a, int b)
Library Prewritten functions in .h files (e.g., strcpy() in <string.h>). #include <string.h>
Recursive A function that calls itself (e.g., factorial, Fibonacci). factorial(n) = n * factorial(n-1)

2. Function Syntax and Components

return_type function_name(parameter_list) {
    // Function body
    return value; // Optional for void functions
}

Key Parts:

  • Return type: Data type of the result (int, float, void).
  • Function name: Identifier (e.g., calculate_sum).
  • Parameters: Inputs to the function (e.g., (int a, int b)).
  • Body: Code block enclosed in {}.
  • Return statement: Sends output back to the caller.

Example: User-Defined Function

// Function to add two numbers
int add(int a, int b) {
    int sum = a + b;
    return sum;
}

How It Works:

  1. Caller passes a = 5, b = 3.
  2. Function computes sum = 5 + 3 = 8.
  3. Returns 8 to the caller.

3. Passing Arguments: By Value vs. By Address

Method How It Works Example Use Case
By Value Copies the actual value (safe, no side effects). add(5, 3) → sum = 8 Immutable data (e.g., constants).
By Address Passes memory address (modifies original data). swap(&x, &y) → swaps x and y. Large data (arrays, structs).
100201302403
Array before/after swap(&arr[1], &arr[2]) via pointers.

Visual: Passing by Address (Pointers)

graph LR
    A["Main Function"] -->|"Passes address"| B["swap(&x, &y)"]
    B --> C["Modifies original x and y"]
    C -->|"Returns nothing"| A

Example: Swap Two Numbers Using Pointers

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

Trace:

Step x (value) y (value) *a (points to) *b (points to)
1 10 20 x (10) y (20)
2 20 10 y (20) x (10)

4. Recursive Functions

Recursion is when a function 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 Using Recursion

int factorial(int n) {
    if (n == 0) // Base case
        return 1;
    else
        return n * factorial(n - 1); // Recursive call
}

Trace for 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)
fact(4)fact(3)fact(2)fact(1)fact(5)
Recursive call stack for factorial(5) with base case fact(1).

Result: 3 * 2 * 1 * 1 = 6.

Advantages of Recursion

  • Elegant code for problems with recursive nature (e.g., trees, graphs).
  • Reduces code complexity (e.g., Fibonacci).

Disadvantages of Recursion

  • Stack overflow if recursion depth is too high (e.g., factorial(10000)).
  • Slower than iteration due to function call overhead.

5. Scope of Variables

Scope Lifetime Accessibility Example
Local Exists while function is executing. Only within the function. int sum = a + b; in add()
Global Entire program. Anywhere after declaration. int count; outside main()
Static Persists across function calls. Only within the function. static int calls = 0;

Example: Static Variable

void counter() {
    static int count = 0; // Retains value between calls
    count++;
    printf("%d ", count);
}

Output for counter(); counter();:

1 2

6. Header Files and Function Prototypes

Header files (.h) contain:

  • Function prototypes (declarations).
  • Macros (e.g., #define PI 3.14).
  • Type definitions (e.g., typedef int integer;).

Example: math.h

// math.h
int add(int a, int b);
float divide(float x, float y);

Usage in .c file:

#include "math.h" // Include the header
int main() {
    printf("%d", add(5, 3)); // Works because of prototype
}

In the Real World

  1. eSewa (Nepal Government)

    • Function Use: The process_payment() function handles user transactions (e.g., electricity bill payments). It takes user_id and amount as inputs, validates them, and returns a success/failure status.
    • Why It Matters: Modularity ensures security (e.g., separate functions for authentication, payment processing).
  2. Khalti (Digital Wallet)

    • Recursion in Algorithms: Khalti’s fraud detection uses recursive tree traversal to analyze transaction patterns (e.g., checking if a series of small transactions form a pyramid scheme).
    • Real Example: A function check_suspicious_transactions(node) calls itself for each child node in a transaction tree.
  3. Pathao (Ride-Hailing App)

    • Pointers for Dynamic Data: Pathao’s update_driver_location() function uses pointers to modify the real-time GPS coordinates of drivers in a linked list (efficient for large-scale updates).
    • Visual:
headDriver 1Driver 2Driver 3NULL
Pathao’s linked list of drivers with next-pointer updates (real-time GPS).
  1. NEPSE (Stock Exchange)
    • Function for Stock Pricing: The calculate_average_price() function takes an array of daily stock prices and returns the average. Passed by address for efficiency with large datasets.
    • Example Code:
      float average_price(float prices[], int size) {
          float sum = 0;
          for (int i = 0; i < size; i++) sum += prices[i];
          return sum / size;
      }
      

7. Practical Example: Array Processing with Functions

Problem: Write a function to find the average of an array passed by address. Solution:

float average(int arr[], int size) {
    int sum = 0;
    for (int i = 0; i < size; i++) sum += arr[i];
    return (float)sum / size;
}

Trace for arr = {10, 20, 30}, size = 3:

Step sum Loop Index (i) arr[i] Calculation
1 10 0 10 sum = 0 + 10 = 10
2 30 1 20 sum = 10 + 20 = 30
3 60 2 30 sum = 30 + 30 = 60
4 - - - return 60 / 3 = 20

Real-World Tie-In:

  • NTC (Nepal Telecom): Uses similar functions to calculate average call durations from a dataset of call_records[].

8. Common Pitfalls and Debugging

  1. Forgetting Return Type:

    • ❌ void add(int a, int b) { return a + b; } → Error: Cannot return int from void.
    • ✅ int add(int a, int b) { return a + b; }.
  2. Incorrect Parameter Passing:

    • ❌ swap(x, y) → Error: Must pass addresses (swap(&x, &y)).
  3. Infinite Recursion:

    • ❌ Missing base case in factorial() → Stack Overflow.
  4. Global Variable Overuse:

    • ❌ int count; → Bad Practice: Can lead to unintended side effects.

Exam Tip

What to Expect in TU/PU Exams

  1. Programming Questions (60% Weight)

    • Task: Write a function to:
      • Sort an array.
      • Find the largest number in a list.
      • Generate Fibonacci series recursively.
    • Tip: Always declare return type, parameters, and use return.
  2. Theory Questions (30% Weight)

    • Topics:
      • Difference between pass by value and pass by address.
      • Advantages/disadvantages of recursion.
      • Role of header files.
    • Tip: Use tables (like above) for comparisons.
  3. Short Notes (10% Weight)

    • Common Questions:
      • "Explain scope rules with examples."
      • "What is a recursive function? Write a program to print Fibonacci series."
    • Tip: Memorize key terms (e.g., "static variables retain value").

Model Answer for a Past Exam Question

Question: Write a program to pass the elements of an array to a function using a pointer and find the sum of the elements. Solution:

#include <stdio.h>

int sum_array(int *arr, int size) {
    int sum = 0;
    for (int i = 0; i < size; i++) sum += arr[i];
    return sum;
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);
    printf("Sum = %d", sum_array(arr, size)); // Output: 15
    return 0;
}

Trace:

Variable arr (address) size Loop (i) arr[i] sum
Initial &arr[0] 5 0 1 0
Step 1 - 5 1 2 1
Step 2 - 5 2 3 3
... - 5 4 5 10
Final - 5 - - 15

Key Formulas to Remember

Concept Formula/Example
Factorial (Recursive) fact(n) = n * fact(n-1); fact(0) = 1
Fibonacci (Recursive) fib(n) = fib(n-1) + fib(n-2); fib(0) = 0
Array Average avg = (sum(arr[i]) / size)
Pointer Arithmetic *(ptr + 1) → Accesses next memory location.

Summary Checklist for Full Marks

Before submitting your answer:

  1. Function Definition:
    • Correct return_type.
    • Proper parameter list.
    • Braces {} for the body.
  2. Recursion:
    • Base case must exist.
    • Recursive case must reduce the problem.
  3. Pointers:
    • Use & to pass addresses.
    • Dereference with * (e.g., *ptr = 10).
  4. Scope:
    • Declare variables close to where they’re used.
    • Avoid global variables unless necessary.
  5. Header Files:
    • Include #include <stdio.h> for I/O.
    • Use #include "custom.h" for user-defined headers.

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

Discussion

Loading…