Functions: Building Blocks of Modular Programming

What Are Functions?

Think of functions like recipes in a cookbook. Instead of writing out how to make chocolate chip cookies every time you want them, you just refer to the recipe. Functions let you write code once and use it many times!

Anatomy of a Function

A function has four main parts, like a machine with input, processing, and output!

Function Components double calculateAverage(int num1, int num2) Return Type What it gives back Function Name How to call it Parameters What it needs { Function Body: The actual code }

Function Types and Examples

graph TD A[Function Types] --> B[No Return, No Parameters] A --> C[Return Value, No Parameters] A --> D[No Return, With Parameters] A --> E[Return Value, With Parameters] B --> F["void greet() {
cout << 'Hello!';
}"] C --> G["int getRandom() {
return rand();
}"] D --> H["void print(string msg) {
cout << msg;
}"] E --> I["int add(int a, int b) {
return a + b;
}"]

Complete Function Examples

// 1. Simple function with no parameters
void printWelcome() {
    cout << "Welcome to the program!" << endl;
    cout << "Let's learn functions!" << endl;
}

// 2. Function with parameters
void greetUser(string name, int age) {
    cout << "Hello, " << name << "!" << endl;
    cout << "You are " << age << " years old." << endl;
}

// 3. Function that returns a value
int square(int number) {
    return number * number;
}

// 4. Function with multiple parameters and return
double calculateBMI(double weight, double height) {
    return weight / (height * height);
}

// 5. Using the functions
int main() {
    printWelcome();                    // Call function with no parameters
    greetUser("Alice", 25);           // Call with parameters
    
    int result = square(5);           // Store return value
    cout << "5 squared is: " << result << endl;
    
    double bmi = calculateBMI(70, 1.75);
    cout << "BMI: " << bmi << endl;
    
    return 0;
}

Function Call Flow

When you call a function, it's like taking a detour - you pause the main road, take the function path, then return where you left off!

Pass by Value vs Pass by Reference

Pass by value is like giving someone a photocopy - they can mark it up without affecting your original. Pass by reference is like giving them your actual document!

Pass by Value vs Pass by Reference Pass by Value x = 10 Original a = 10 Copy void change(int a) { a = 20; } int x = 10; change(x); // x is still 10! Pass by Reference x = 10 Original Reference void change(int &a) { a = 20; } int x = 10; change(x); // x is now 20!

Reference Parameter Examples

// Pass by value - original unchanged
void tryToDouble(int num) {
    num = num * 2;
    cout << "Inside function: " << num << endl;
}

// Pass by reference - original changed
void actuallyDouble(int &num) {
    num = num * 2;
    cout << "Inside function: " << num << endl;
}

// Swap function - classic reference example
void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

// Using const reference for large objects (efficient, read-only)
void printArray(const int arr[], int size) {
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

int main() {
    int x = 10;
    
    tryToDouble(x);
    cout << "After tryToDouble: " << x << endl;  // Still 10
    
    actuallyDouble(x);
    cout << "After actuallyDouble: " << x << endl;  // Now 20
    
    int a = 5, b = 8;
    swap(a, b);
    cout << "a=" << a << ", b=" << b << endl;  // a=8, b=5
    
    return 0;
}

Function Overloading: Same Name, Different Jobs

Function overloading is like having multiple tools with the same name but different uses - a "cut" function might cut paper, fabric, or video!

Function Overloading Example

// Different parameter types
int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}

// Different number of parameters
int add(int a, int b, int c) {
    return a + b + c;
}

// Different parameter order
void display(int num, string text) {
    cout << "Number: " << num << ", Text: " << text << endl;
}

void display(string text, int num) {
    cout << "Text: " << text << ", Number: " << num << endl;
}

int main() {
    cout << add(5, 3) << endl;         // Calls int version: 8
    cout << add(5.5, 3.2) << endl;     // Calls double version: 8.7
    cout << add(1, 2, 3) << endl;      // Calls three-parameter version: 6
    
    display(42, "Answer");             // Number: 42, Text: Answer
    display("Answer", 42);             // Text: Answer, Number: 42
    
    return 0;
}

Default Parameters: Optional Values

Default parameters are like restaurant orders - "I'll have the usual" means you get your default choice!

graph TD A[Function with Defaults] --> B["greet(name, greeting='Hello')"] B --> C["greet('Alice')"] B --> D["greet('Bob', 'Hi')"] C --> E["Uses default: 'Hello Alice'"] D --> F["Uses provided: 'Hi Bob'"]
// Function with default parameters
void greet(string name, string greeting = "Hello") {
    cout << greeting << ", " << name << "!" << endl;
}

// Multiple defaults (must be rightmost)
void createWindow(int width = 800, int height = 600, string title = "My Window") {
    cout << "Creating " << width << "x" << height << " window: " << title << endl;
}

int main() {
    greet("Alice");                    // Uses default: "Hello, Alice!"
    greet("Bob", "Hi");               // Uses provided: "Hi, Bob!"
    
    createWindow();                    // All defaults: 800x600 "My Window"
    createWindow(1024, 768);          // Custom size, default title
    createWindow(1920, 1080, "Game"); // All custom values
    
    return 0;
}

Function Prototypes: Declare First, Define Later

Function prototypes are like movie trailers - they tell you what's coming without showing the whole thing!

Function Organization Without Prototypes ❌ Order matters! // Must define first int add(int a, int b) { return a + b; } // Then use int main() { add(5, 3); } With Prototypes ✓ Flexible organization! // Prototype at top int add(int a, int b); int main() { add(5, 3); // Can use! } // Define anywhere int add(int a, int b) { return a + b; }

Recursion: Functions Calling Themselves

Recursion is like Russian nesting dolls - each doll contains a smaller version of itself until you reach the smallest one!

Recursion Examples

// Factorial: n! = n × (n-1) × ... × 1
int factorial(int n) {
    if (n <= 1) {          // Base case
        return 1;
    }
    return n * factorial(n - 1);  // Recursive case
}

// Fibonacci sequence
int fibonacci(int n) {
    if (n <= 1) {          // Base cases
        return n;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// Sum of array elements recursively
int sumArray(int arr[], int size) {
    if (size == 0) {       // Base case: empty array
        return 0;
    }
    return arr[size - 1] + sumArray(arr, size - 1);
}

// Palindrome checker
bool isPalindrome(string str, int start, int end) {
    if (start >= end) {    // Base case: middle reached
        return true;
    }
    if (str[start] != str[end]) {
        return false;
    }
    return isPalindrome(str, start + 1, end - 1);
}

Practice Exercise: Calculator Functions

Build a Modular Calculator

Create a calculator using functions for each operation:

  1. Functions for add, subtract, multiply, divide
  2. A display menu function
  3. Input validation function
  4. Main calculator loop
#include <iostream>
using namespace std;

// TODO: Create function prototypes here

int main() {
    int choice;
    double num1, num2, result;
    
    do {
        displayMenu();
        cin >> choice;
        
        if (choice >= 1 && choice <= 4) {
            cout << "Enter two numbers: ";
            cin >> num1 >> num2;
            
            // TODO: Call appropriate function based on choice
            
            cout << "Result: " << result << endl;
        }
    } while (choice != 5);
    
    return 0;
}
Function Signatures
double add(double a, double b);
double subtract(double a, double b);
double multiply(double a, double b);
double divide(double a, double b);
void displayMenu();
bool isValidChoice(int choice);

Function Best Practices

graph TD A[Function Best Practices] --> B[Single Responsibility] A --> C[Descriptive Names] A --> D[Reasonable Parameters] A --> E[Document Purpose] B --> F[One function, one job] C --> G[calculateAverage not calc] D --> H[3-4 parameters max] E --> I[Comments explain why]

Common Function Patterns

Common Function Patterns Validator Pattern bool isValid(int value) { return value >= 0 && value <= 100; } Calculator Pattern double calculate(double a, double b) { return /* some formula */; } Converter Pattern double toMeters(double feet) { return feet * 0.3048; } Finder Pattern int findMax(int arr[], int size) { /* search logic */ } Display Pattern void printReport(/* data */) { /* format and display */ }

Challenge Exercise: Text Adventure Game

Advanced Function Challenge

Create a text adventure game using functions for:

  1. Room descriptions
  2. Player movement
  3. Inventory management
  4. Combat system
  5. Save/Load game state
Structure Hints

Key Takeaways

graph LR A[Master Functions] --> B[Write Modular Code] B --> C[Reuse Solutions] C --> D[Build Complex Programs] D --> E[Professional Software!]