CACS151 C Programming

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

printf()scanf()malloc()Library FunctionsCustom logicReusable code blocksUser-Defined FunctionsFunctions
Hierarchy of function types in C

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

5071
Call-by-value: Original array unchanged after function call
100201302address of arr[0]address of arr[2]
Call-by-reference: Function modifies original array

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:

  1. Base Case: Terminates recursion (e.g., factorial(0) = 1).
  2. 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

  1. Infinite Recursion: Forgetting the base case.
    int infinite() {
        infinite(); // Stack overflow!
    }
    
  2. Memory Leaks: Forgetting to free() allocated memory.
    int *ptr = malloc(sizeof(int));
    // ptr is never freed!
    
  3. Incorrect Argument Passing: Mixing call-by-value/reference.
    void incorrect(int x) { x = 10; } // Won’t modify original
    

8. Exam Tips

  1. Function Definition:

    • Always declare return type and parameters.
    • Use meaningful names (e.g., calculateArea() instead of func1()).
  2. 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.
  3. Recursion:

    • Always include a base case to terminate recursion.
    • Trace the call stack (like the factorial example above).
    • Common patterns:
      • Fibonacci series.
      • Tower of Hanoi.
      • Tree traversals (in-unit 7).
  4. DMA:

    • Check for NULL after malloc/calloc to 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."
  5. Code Structure:

    • Declare functions before main() or use prototypes.
    • Example:
      int add(int, int); // Prototype
      int main() { ... }
      int add(int a, int b) { ... } // Definition
      

9. Practice Problems

  1. Write a function to check if a number is prime.
  2. Use recursion to print the Fibonacci series up to the 10th term.
  3. DMA: Create an array of 10 integers dynamically and sort it in ascending order.
  4. Call-by-reference: Write a function to reverse a string (pass the string as a pointer).
  5. Real-world: Simulate a bank ATM with functions for deposit(), withdraw(), and checkBalance().

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 result

Based on the TU BCA syllabus for C Programming (CACS151), unit 6.

Discussion

Loading…