Unit 4: Functions

A function is a self-contained block of code that performs a specific task. Functions are the building blocks of C programs, allowing for modularity (breaking code into small pieces) and reusability (using the same code multiple times).

Table of Contents

Defining a Function

Function Components

A function definition has four main parts:

  1. Return Type: The data type of the value the function sends back (e.g., int, float, or void if it returns nothing).
  2. Function Name: A unique name to identify the function (e.g., addNumbers).
  3. Parameters (or Arguments): A list of variables that receive values when the function is called. This is how you pass data *into* the function.
  4. Function Body: The block of code { ... } that performs the function's task.

Function Definition

This is the full implementation of the function.

Syntax:

return_type function_name(type param1, type param2) {
    // Code block (body)
    return value; // 'value' must match the return_type
}

Example:

int add(int a, int b) {
    int sum = a + b;
    return sum; // Returns an integer value
}

Function Call

To execute a function, you "call" it from main() or another function.

int main() {
    int result;
    result = add(10, 5); // Function call
    printf("The result is %d\n", result); // Prints "The result is 15"
    return 0;
}

Function Prototypes

A function prototype (or declaration) is a single line that tells the compiler about a function *before* it is defined. It must appear before the function is first called (usually at the top of the file, before main()).

Why? The C compiler reads code from top to bottom. If you call a function before it's defined, the compiler doesn't know what it is and gives an error.

Syntax: return_type function_name(data_type1, data_type2, ...);
(Note the semicolon at the end and the lack of variable names, though names are optional).

#include <stdio.h>

// Function Prototype 
int add(int, int);

int main() {
    // Now the compiler knows what 'add' is, so this call is valid.
    int result = add(10, 5); 
    printf("Result: %d\n", result);
    return 0;
}

// Function Definition (can now be placed after main) 
int add(int a, int b) {
    return a + b;
}

Passing Arguments to a Function

This describes how data is sent *into* a function. C has two methods:

Pass by Value (The Default)

This is the default method in C. A copy of the argument's value is passed to the function.
Consequence: The function can modify its local copy, but it cannot change the original variable in the calling function (e.g., in main()).

Pass by Reference (Simulated with Pointers)

C does not technically have "pass by reference," but it can be simulated by passing pointers (memory addresses) as arguments.
Consequence: The function receives the *actual memory address* of the original variable. By "dereferencing" this pointer, the function can change the original variable.

Code Examples (from Practicals)

Pass by Value vs. Pass by Reference

This code clearly demonstrates the difference by trying to swap two numbers.

#include <stdio.h>

// Prototype for pass-by-value
void swap_by_value(int a, int b);
// Prototype for pass-by-reference (using pointers)
void swap_by_reference(int *a, int *b);

int main() {
    int x = 10, y = 20;
    
    printf("Original: x = %d, y = %d\n", x, y);
    
    // 1. Pass by Value (fails to swap)
    swap_by_value(x, y);
    printf("After swap_by_value: x = %d, y = %d\n", x, y);

    // 2. Pass by Reference (succeeds)
    swap_by_reference(&x, &y); // Pass the addresses of x and y
    printf("After swap_by_reference: x = %d, y = %d\n", x, y);

    return 0;
}

// This function gets COPIES of x and y.
void swap_by_value(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    // a and b are swapped here, but x and y in main() are unchanged.
}

// This function gets the MEMORY ADDRESSES of x and y.
void swap_by_reference(int *a, int *b) {
    // *a means "the value at the address a"
    int temp = *a;
    *a = *b;
    *b = temp;
    // This swaps the original values in main().
}

Expected Output:
Original: x = 10, y = 20
After swap_by_value: x = 10, y = 20 (Failed)
After swap_by_reference: x = 20, y = 10 (Succeeded)

Practical #5b: Factorial using a Recursive Function

Recursion is a special case of a function call where a function calls *itself*. It must have a base case to stop the recursion.

#include <stdio.h>

// Prototype for recursive factorial
long long factorial(int n);

int main() {
    int num = 5;
    long long fact = factorial(num);
    printf("Factorial of %d is %lld\n", num, fact);
    return 0;
}

// Recursive function definition
long long factorial(int n) {
    // Base Case: Stops the recursion
    if (n == 0 || n == 1) {
        return 1;
    } 
    // Recursive Step: Calls itself with a smaller problem
    else {
        return n * factorial(n - 1);
    }
}
// How it works for factorial(4):
// 4 * factorial(3)
// 4 * (3 * factorial(2))
// 4 * (3 * (2 * factorial(1)))
// 4 * (3 * (2 * 1)) = 24

Unit 4: Exam Quick Tips