Skillversitas

Functions in C++

A function is a block of code that can be called repeatedly to perform a specific task. Functions help organize code, reduce duplication, and make programs easier to read and maintain.

Every function has: a return type (the type of the returned value, or void if there is none), a function name, a parameter list (the inputs it receives), and a body (the code that runs). Functions can be declared before use (prototype) or defined directly.

Declaration vs Definition

  • Prototype (declaration): Tells the compiler about the function's existence. Example: int add(int, int);
  • Definition: Contains the function's actual code. Example: int add(int a, int b) { return a + b; }

The prototype is placed before main() or in a header file. The definition can be placed after main().

Pass by Value vs Pass by Reference

  • Pass by value: The function receives a copy of the parameter. Changes do not affect the original variable.
  • Pass by reference: The function receives the parameter's address. Changes affect the original variable. Uses the & operator on the parameter.

Inline and constexpr Functions

  • Inline: A hint for the compiler to replace the function call with the function's code directly (avoiding call overhead). Useful for small functions.
  • constexpr: A function that can be evaluated at compile time. The value is known before the program runs.

Code Example

#include <iostream>
#include <string>
using namespace std;

// Function prototypes
int add(int a, int b);
double divide(double a, double b);
void sayHello(string name);
bool isPrime(int n);
int factorial(int n);

// Inline function
inline int square(int x) {
    return x * x;
}

// constexpr function (C++11)
constexpr double circleArea(double r) {
    return 3.14159265358979 * r * r;
}

// Function overloading (basic)
int add(int a, int b, int c) {
    return a + b + c;
}

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

// Void function
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

// Pass by value
void doubleByValue(int x) {
    x *= 2;
    cout << "Inside the function (by value): " << x << endl;
}

// Pass by reference
void doubleByReference(int& x) {
    x *= 2;
    cout << "Inside the function (by reference): " << x << endl;
}

// Pass by const reference
void printInfo(const string& name, int age) {
    cout << "Name: " << name << ", Age: " << age << endl;
}

// Return multiple values via reference
void minMax(int arr[], int size, int& min, int& max) {
    min = arr[0];
    max = arr[0];
    for (int i = 1; i < size; i++) {
        if (arr[i] < min) min = arr[i];
        if (arr[i] > max) max = arr[i];
    }
}

// Default parameter
void greet(string name, string prefix = "Hello") {
    cout << prefix << ", " << name << "!" << endl;
}

// Recursive function
int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

// Function returning a pointer
int* findMax(int* arr, int size) {
    int* largest = &arr[0];
    for (int i = 1; i < size; i++) {
        if (arr[i] > *largest) {
            largest = &arr[i];
        }
    }
    return largest;
}

int main() {
    // Calling functions
    int result = add(5, 3);
    cout << "5 + 3 = " << result << endl;

    double divisionResult = divide(10.0, 3.0);
    cout << "10 / 3 = " << divisionResult << endl;

    sayHello("John");

    // Overloading
    cout << "\nOverloading:" << endl;
    cout << "add(5, 3) = " << add(5, 3) << endl;
    cout << "add(5, 3, 2) = " << add(5, 3, 2) << endl;
    cout << "add(5.5, 3.3) = " << add(5.5, 3.3) << endl;

    // Inline function
    cout << "\nInline: square(7) = " << square(7) << endl;

    // Constexpr
    constexpr double area = circleArea(5.0);
    cout << "Circle area r=5: " << area << endl;

    // Pass by value vs reference
    int val = 10;
    cout << "\nOriginal: " << val << endl;
    doubleByValue(val);
    cout << "After by value: " << val << endl;

    doubleByReference(val);
    cout << "After by reference: " << val << endl;

    // Const reference
    string name = "Mike";
    printInfo(name, 25);

    // Return multiple values
    int numbers[] = {3, 1, 4, 1, 5, 9, 2, 6};
    int min, max;
    minMax(numbers, 8, min, max);
    cout << "\nMin: " << min << ", Max: " << max << endl;

    // Void function
    cout << "\nArray: ";
    printArray(numbers, 8);

    // Default parameter
    cout << "\nDefault parameter:" << endl;
    greet("John");
    greet("Mike", "Good morning");

    // Recursive
    cout << "\nFactorial 5: " << factorial(5) << endl;

    // Function returning a pointer
    int* ptrMax = findMax(numbers, 8);
    cout << "Max: " << *ptrMax << " (address: " << ptrMax << ")" << endl;

    // Prime check
    cout << "\nPrime numbers up to 20:" << endl;
    for (int i = 2; i <= 20; i++) {
        if (isPrime(i)) {
            cout << i << " ";
        }
    }
    cout << endl;

    return 0;
}

// Function definitions
int add(int a, int b) {
    return a + b;
}

double divide(double a, double b) {
    if (b == 0) {
        cout << "Error: Division by zero!" << endl;
        return 0;
    }
    return a / b;
}

void sayHello(string name) {
    cout << "Hello, " << name << "! Happy learning C++!" << endl;
}

bool isPrime(int n) {
    if (n < 2) return false;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) return false;
    }
    return true;
}

Code Explanation

  • int add(int a, int b); — A function prototype. Tells the compiler that this function exists, with specific parameters and a return type. Placed at the top of the file.
  • int add(int a, int b) { return a + b; } — A function definition. Contains the actual code. It can be placed after main().
  • void sayHello(string name) — A void function returns no value. It only performs an action (here, printing to the screen).
  • inline int square(int x) — A hint for the compiler to replace the call square(7) directly with the code 7 * 7. Eliminates function overhead. Effective for small functions.
  • constexpr double circleArea(double r) — A function that can be evaluated at compile time. constexpr double area = circleArea(5.0); is computed at compile time, not at runtime.
  • Overloading: Several functions with the same name but different parameters. add(int, int), add(int, int, int), and add(double, double) are three different functions. The compiler chooses based on the number and type of the arguments.
  • void doubleByValue(int x) — The parameter x is a copy. Changing x only affects the copy, not the original variable.
  • void doubleByReference(int& x) — & indicates a reference. x is an alias for the original variable. Changing x directly changes the original variable.
  • const string& name — A const reference. Safe because it cannot modify name, and there is no copy overhead.
  • void minMax(..., int& min, int& max) — Returns two values through reference parameters. The function fills in min and max directly.
  • void greet(string name, string prefix = "Hello") — A default parameter. If prefix is not given, it uses "Hello". Defaults must be on the right (no non-default parameters after them).
  • int factorial(int n) — A recursive function. It calls itself with a smaller input until it reaches the base case (n <= 1).
  • int* findMax(...) — Returns a pointer to the largest element in an array. The caller receives that element's address.
  • bool isPrime(int n) — Checks for prime numbers by iterating up to the square root of n. Returns true or false.

Everyday Use Cases

Calculator: The functions add, divide, subtract, and multiply form a calculator module. Each function is separate and can be tested independently.

Input validation: A function bool isValidEmail(string email) tests the email format. It can be called repeatedly from various parts of a program.

Data processing: The minMax() function finds the minimum and maximum values from an array of sensor readings. Two values are returned at once through reference parameters.

Conclusion

Functions are the main building blocks of a C++ program. A prototype declares a function before its definition. Pass by value is safe but has copy overhead for large objects. Pass by reference is efficient and allows direct modification. constexpr enables compile-time evaluation. A good function has a single responsibility, a descriptive name, and minimal parameters.