BIT102 C Programming

C ProgrammingUnit 610 min read

Functions in C: Declaration, Definition, Calling, Types, and Applications

Unit 6 of C Programming: Explores functions as modular building blocks—how to define, declare, call, and use them (including recursion, scope, storage classes, and passing arrays/strings)—with practical examples, code traces, and real-world ties to apps like Daraz and eSewa.

Why Functions?

Functions are reusable blocks of code that perform a specific task. They improve modularity, readability, and maintainability by breaking programs into smaller, manageable parts.


1. Function Basics

Definition

A function is a named sequence of statements that performs a task and optionally returns a value.

100201302
Example array passed to a function (before modification)

Syntax

return_type function_name(parameter_list) {
    // statements
    return value; // optional
}

Key Components

  • Return Type: Specifies the type of value returned (e.g., int, void).
  • Function Name: Must follow C naming rules (no spaces, starts with a letter).
  • Parameters: Inputs passed to the function (optional).
  • Body: Statements executed when the function is called.
  • Return Statement: Optional; exits the function and returns a value.

2. Function Declaration vs. Definition

Declaration Definition
Tells the compiler the function exists. Provides the actual code.
Syntax: return_type function_name(parameters); Syntax: Full function body.
Example: int sum(int a, int b); Example: int sum(int a, int b) { return a + b; }

3. Calling a Function

Functions are called using their name followed by arguments (if any). Example:

#include <stdio.h>
int add(int x, int y) {
    return x + y;
}
int main() {
    int result = add(5, 3); // Function call
    printf("Result: %d\n", result);
    return 0;
}

Output:

Result: 8

4. Types of Functions

(a) Library Functions

Predefined functions in C (e.g., printf, scanf from <stdio.h>).

(b) User-Defined Functions

Functions written by the programmer (e.g., add, factorial).

(c) Recursive Functions

A function calls itself to solve smaller instances of the same problem. Example: Factorial using recursion.

flowchart TD
  A["main()"] --> B["call factorial(5)"]
  B --> C["factorial(5) calls factorial(4)"]
  C --> D["factorial(4) calls factorial(3)"]
  D --> E["factorial(3) calls factorial(2)"]
  E --> F["factorial(2) calls factorial(1)"]
  F --> G["factorial(1) returns 1"]
  G -->|"1"| H["factorial(2) returns 2*1"]
  H -->|"2"| I["factorial(3) returns 3*2"]
  I -->|"6"| J["factorial(4) returns 4*6"]
  J -->|"24"| K["factorial(5) returns 5*24"]
  K --> L["main() prints 120"]

Code Example:

#include <stdio.h>
int factorial(int n) {
    if (n == 0) return 1;
    return n * factorial(n - 1);
}
int main() {
    printf("Factorial of 5: %d\n", factorial(5));
    return 0;
}

Trace Table:

Step Function Call Return Value
1 factorial(5) -
2 factorial(4) -
3 factorial(3) -
4 factorial(2) -
5 factorial(1) 1
6 factorial(2) 2
7 factorial(3) 6
8 factorial(4) 24
9 factorial(5) 120

5. Scope and Storage Classes

(a) Local Variables

  • Declared inside a function.
  • Accessible only within that function.
  • Example:
    int add(int a, int b) {
        int sum = a + b; // Local variable
        return sum;
    }
    

(b) Global Variables

  • Declared outside all functions.
  • Accessible throughout the program.
  • Example:
    int global_var = 10; // Global variable
    int main() {
        printf("%d\n", global_var);
        return 0;
    }
    

(c) Storage Classes

Storage Class Scope Lifetime Example
auto Local Function call int x;
static Local/Global Program lifetime static int x;
extern Global Program lifetime extern int y;
register Local Function call register int x;

6. Passing Arguments to Functions

(a) Pass by Value

  • A copy of the variable is passed.
  • Changes inside the function do not affect the original.
  • Example:
    void increment(int x) {
        x++; // Does not affect original 'a'
    }
    int main() {
        int a = 5;
        increment(a);
        printf("%d\n", a); // Output: 5
        return 0;
    }
    

(b) Pass by Reference (Using Pointers)

  • The address of the variable is passed.
  • Changes inside the function affect the original.
  • Example:
    void increment(int *x) {
        (*x)++; // Modifies original 'a'
    }
    int main() {
        int a = 5;
        increment(&a);
        printf("%d\n", a); // Output: 6
        return 0;
    }
    
1000201302ptr

7. Returning Arrays/Strings from Functions

(a) Returning an Array

  • Arrays cannot be returned directly; use pointers.
  • Example:
    int* getArray() {
        int arr[] = {1, 2, 3};
        return arr; // Returns pointer to array
    }
    int main() {
        int *ptr = getArray();
        printf("%d\n", ptr[1]); // Output: 2
        return 0;
    }
    

(b) Returning a String

  • Strings are arrays of characters; return their address.
  • Example:
    char* greet() {
        char msg[] = "Hello";
        return msg; // Returns pointer to string
    }
    int main() {
        char *str = greet();
        printf("%s\n", str); // Output: Hello
        return 0;
    }
    

8. Variable Arguments (Varargs)

  • Functions that accept a variable number of arguments.
  • Use stdarg.h header.
  • Example:
    #include <stdio.h>
    #include <stdarg.h>
    int sum(int count, ...) {
        va_list args;
        va_start(args, count);
        int total = 0;
        for (int i = 0; i < count; i++) {
            total += va_arg(args, int);
        }
        va_end(args);
        return total;
    }
    int main() {
        printf("%d\n", sum(3, 1, 2, 3)); // Output: 6
        return 0;
    }
    

9. Inline Functions

  • Functions expanded at compile time to avoid function call overhead.
  • Use __inline__ or inline keyword.
  • Example:
    inline int square(int x) {
        return x * x;
    }
    int main() {
        printf("%d\n", square(5)); // Compiled as `5 * 5`
        return 0;
    }
    

10. Macro vs. Function

Macro Function
Text substitution. Actual code execution.
Defined using #define. Defined using return_type.
No type checking. Type checking.
Example: #define PI 3.14 Example: float circleArea(float r) { return PI * r * r; }

In the Real World

  1. Daraz Order Processing

    • Idea: Functions handle different steps (e.g., calculateShippingCost(), updateInventory()).
    • How: Each function modularizes a task (e.g., processPayment() for checkout).
  2. eSewa Transaction Validation

    • Idea: Functions validate user input (e.g., isValidAmount(), checkBalance()).
    • Worked Example: If a user inputs ₹1000, isValidAmount(1000) returns true if the amount is within limits.
  3. Pathao Ride Routing

    • Idea: Functions calculate routes (e.g., findShortestPath(), estimateFare()).
    • Real Tie: Uses Dijkstra’s algorithm (implemented as functions) to compute the fastest route between two points.

Exam Tip

  • Focus Areas:
    • Function Declaration/Definition: Always include return type and parameter list.
    • Recursion: Practice tracing recursive calls (e.g., factorial, Fibonacci).
    • Passing Arguments: Differentiate pass-by-value vs. pass-by-reference.
    • Varargs: Know how to use va_list, va_start, and va_arg.
  • Common Mistakes:
    • Forgetting to return a value in non-void functions.
    • Incorrectly passing arrays (use pointers).
    • Misusing global/local variables.
  • Practice Questions:
    • Write a function to reverse a string using recursion.
    • Implement a function to sort an array (e.g., bubble sort).
    • Create a program with multiple functions handling different tasks (e.g., calculateArea(), printMenu()).

Worked Example: Sorting an Array Using Functions

Task: Sort an array of 10 integers in ascending order using a function.

#include <stdio.h>
void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
int main() {
    int arr[] = {64, 34, 25, 12, 22, 11, 90};
    int n = sizeof(arr) / sizeof(arr[0]);
    bubbleSort(arr, n);
    printf("Sorted array: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

Output:

Sorted array: 11 12 22 25 34 64 90

Visuals

Figure 1: Function Call Stack Trace

flowchart TD
    A["main()"] --> B["call factorial(3)"]
    B --> C["factorial(3) calls factorial(2)"]
    C --> D["factorial(2) calls factorial(1)"]
    D --> E["factorial(1) returns 1"]
    E --> F["factorial(2) returns 2"]
    F --> G["factorial(3) returns 6"]
    G --> H["main() prints 6"]

Figure 2: Pass by Value vs. Pass by Reference

flowchart TD
    A["Original Array: [10, 20, 30]"] --> B["Pass by Value"]
    B --> C["Function Receives Copy: [10, 20, 30]"]
    C --> D["Modification Inside Function: [100, 20, 30]"]
    D --> E["Original Array Unchanged: [10, 20, 30]"]

    A --> F["Pass by Reference"]
    F --> G["Function Receives Address"]
    G --> H["Modification Inside Function: [100, 20, 30]"]
    H --> I["Original Array Modified: [100, 20, 30]"]

Summary Table

Concept Key Points
Function Declaration Syntax: return_type func_name(parameters);
Recursion Function calls itself; use base case to stop recursion.
Pass by Value Copy of variable is passed; original unchanged.
Pass by Reference Address of variable is passed; original modified.
Varargs Use stdarg.h for variable arguments.
Inline Functions Expanded at compile time for efficiency.

Based on the TU BIT syllabus for C Programming (BIT102), unit 6.

Discussion

Loading…