Docs

README

Function Basics in C++

Table of Contents

  1. Introduction
  2. What are Functions?
  3. Function Declaration and Definition
  4. Function Components
  5. Return Types
  6. The main() Function
  7. Function Call Mechanism
  8. Function Scope
  9. Header Files and Function Organization
  10. Default Arguments
  11. Function Best Practices
  12. Summary

Introduction

Functions are the fundamental building blocks of C++ programs. They allow you to:

  • Organize code into reusable, manageable units
  • Avoid repetition by writing code once and calling it multiple times
  • Abstract complexity by hiding implementation details
  • Improve readability through descriptive function names
  • Enable testing by isolating functionality

Why Functions Matter

// Without functions (repetitive, hard to maintain)
int sum1 = 0;
for (int i = 0; i < 10; i++) sum1 += arr1[i];
int sum2 = 0;
for (int i = 0; i < 20; i++) sum2 += arr2[i];

// With functions (clean, reusable)
int sum1 = calculateSum(arr1, 10);
int sum2 = calculateSum(arr2, 20);

What are Functions?

A function is a named block of code that:

  1. Performs a specific task
  2. Can accept input (parameters)
  3. Can produce output (return value)
  4. Can be called from other parts of the program

Anatomy of a Function

//    Return Type    Function Name    Parameters
//         ↓              ↓               ↓
         int           add         (int a, int b)
{                                          // ← Function Body Begins
    return a + b;                          // ← Statement(s)
}                                          // ← Function Body Ends

Types of Functions

TypeDescriptionExample
User-definedCreated by programmercalculateTax()
LibraryProvided by C++ standard librarysqrt(), strlen()
MemberBelongs to a classmyObject.display()
FreeNot part of any classprintMessage()

Function Declaration and Definition

Declaration (Prototype)

A declaration tells the compiler about a function's:

  • Name
  • Return type
  • Parameters (types and number)
// Function declarations (prototypes)
int add(int a, int b);              // Parameter names optional
double calculateArea(double);        // Parameter name omitted
void printMessage();                 // No parameters
string formatName(string, string);   // Multiple parameters

Definition (Implementation)

A definition provides the actual code:

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

double calculateArea(double radius) {
    return 3.14159 * radius * radius;
}

void printMessage() {
    cout << "Hello, World!" << endl;
}

Declaration vs Definition

// Declaration (usually in header file .h)
int multiply(int x, int y);

// Definition (usually in source file .cpp)
int multiply(int x, int y) {
    return x * y;
}

Why Separate Declaration?

  1. Forward declaration: Use function before defining it
  2. Multiple files: Share functions across files
  3. Header files: Organize interfaces
  4. Compilation: Compiler needs to know function signature

Function Components

1. Return Type

Specifies what type of value the function returns:

int getAge()          // Returns integer
double getPrice()     // Returns double
string getName()      // Returns string
bool isValid()        // Returns boolean
void printInfo()      // Returns nothing

2. Function Name

Rules for function names:

  • Start with letter or underscore
  • Contains letters, digits, underscores
  • Case-sensitive
  • Cannot be a reserved keyword
// Good names (descriptive)
int calculateTotal()
bool isValidEmail()
void processPayment()
string formatDate()

// Poor names (avoid)
int calc()       // Too short
int x()          // Meaningless
int foo123()     // Not descriptive

3. Parameters (Arguments)

Data passed into the function:

// No parameters
void greet() {
    cout << "Hello!" << endl;
}

// One parameter
void printNumber(int n) {
    cout << "Number: " << n << endl;
}

// Multiple parameters
int add(int a, int b, int c) {
    return a + b + c;
}

// Mixed types
void displayInfo(string name, int age, double salary) {
    cout << name << " is " << age << " years old." << endl;
}

4. Function Body

The code block that executes:

int factorial(int n) {
    // ← Body starts
    int result = 1;
    for (int i = 2; i <= n; i++) {
        result *= i;
    }
    return result;
    // ← Body ends
}

5. Return Statement

Exits the function and optionally returns a value:

int max(int a, int b) {
    if (a > b) {
        return a;    // Early return
    }
    return b;        // Normal return
}

void printPositive(int n) {
    if (n <= 0) {
        return;      // Early exit (no value)
    }
    cout << n << endl;
}

Return Types

Fundamental Types

int getInteger() { return 42; }
double getDouble() { return 3.14; }
char getChar() { return 'A'; }
bool getBool() { return true; }

void - No Return Value

void printGreeting() {
    cout << "Hello!" << endl;
    // No return statement needed (implicit return)
}

void logError(string message) {
    cerr << "Error: " << message << endl;
    return;  // Optional explicit return
}

Returning Objects

#include <string>
#include <vector>

string getFullName(string first, string last) {
    return first + " " + last;
}

vector<int> getEvenNumbers(int max) {
    vector<int> evens;
    for (int i = 2; i <= max; i += 2) {
        evens.push_back(i);
    }
    return evens;  // Returns copy (or moved with RVO)
}

auto Return Type (C++14)

auto add(int a, int b) {
    return a + b;  // Deduced as int
}

auto getPI() {
    return 3.14159;  // Deduced as double
}

Trailing Return Type (C++11)

auto add(int a, double b) -> double {
    return a + b;
}

// Useful with templates
template<typename T, typename U>
auto multiply(T a, U b) -> decltype(a * b) {
    return a * b;
}

The main() Function

The entry point of every C++ program.

Standard Forms

// Form 1: No parameters
int main() {
    // Program code
    return 0;  // Success
}

// Form 2: With command-line arguments
int main(int argc, char* argv[]) {
    // argc = argument count
    // argv = argument values
    return 0;
}

// Alternative Form 2
int main(int argc, char** argv) {
    return 0;
}

Return Values

Return ValueMeaning
0Successful execution
Non-zeroError occurred
EXIT_SUCCESSMacro for success (typically 0)
EXIT_FAILUREMacro for failure (typically 1)
#include <cstdlib>

int main() {
    if (/* error condition */) {
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Command-Line Arguments

int main(int argc, char* argv[]) {
    cout << "Number of arguments: " << argc << endl;

    for (int i = 0; i < argc; i++) {
        cout << "argv[" << i << "] = " << argv[i] << endl;
    }

    return 0;
}

// Run: ./program arg1 arg2 arg3
// Output:
// Number of arguments: 4
// argv[0] = ./program
// argv[1] = arg1
// argv[2] = arg2
// argv[3] = arg3

Function Call Mechanism

How Function Calls Work

  1. Push arguments onto the call stack
  2. Push return address (where to continue after function)
  3. Jump to function code
  4. Execute function body
  5. Push return value (if any)
  6. Pop stack frame and return

Call Stack Visualization

Before call:         During call:         After return:
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│    main()    │     │    main()    │     │    main()    │
│              │     │              │     │              │
│  int x = 5   │     │  int x = 5   │     │  int x = 5   │
│  int y = 3   │     │  int y = 3   │     │  int y = 3   │
│              │     ├──────────────┤     │  int z = 8   │
│  add(x, y)   │     │    add()     │     │              │
│              │     │  a = 5       │     └──────────────┘
└──────────────┘     │  b = 3       │
                     │  return 8    │
                     └──────────────┘

Calling a Function

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

int main() {
    // Direct call
    int result1 = add(5, 3);

    // Call with variables
    int x = 10, y = 20;
    int result2 = add(x, y);

    // Nested calls
    int result3 = add(add(1, 2), add(3, 4));  // add(3, 7) = 10

    // Expression in argument
    int result4 = add(x * 2, y - 5);  // add(20, 15)

    return 0;
}

Function Scope

Local Variables

Variables declared inside a function exist only within that function:

void example() {
    int local = 10;      // Local to example()
    cout << local;       // OK
}

int main() {
    example();
    // cout << local;    // ERROR! local is not visible here
    return 0;
}

Scope Hierarchy

int global = 100;        // Global scope

void outer() {
    int outer_var = 50;  // Local to outer()

    {   // Inner block
        int inner_var = 25;  // Local to this block
        cout << global;      // OK - global visible
        cout << outer_var;   // OK - outer scope visible
        cout << inner_var;   // OK - current scope
    }

    // cout << inner_var;   // ERROR - out of scope
}

Static Local Variables

Persist between function calls:

void counter() {
    static int count = 0;  // Initialized once
    count++;
    cout << "Called " << count << " times" << endl;
}

int main() {
    counter();  // Called 1 times
    counter();  // Called 2 times
    counter();  // Called 3 times
    return 0;
}

Global Variables

Accessible from any function (use sparingly):

int globalCounter = 0;  // Global

void increment() {
    globalCounter++;
}

void print() {
    cout << globalCounter << endl;
}

int main() {
    increment();
    increment();
    print();  // Output: 2
    return 0;
}

Header Files and Function Organization

Header File (.h or .hpp)

Contains declarations:

// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

// Function declarations
int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);
double divide(int a, int b);

#endif

Source File (.cpp)

Contains definitions:

// math_utils.cpp
#include "math_utils.h"

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

int subtract(int a, int b) {
    return a - b;
}

int multiply(int a, int b) {
    return a * b;
}

double divide(int a, int b) {
    if (b == 0) throw runtime_error("Division by zero");
    return static_cast<double>(a) / b;
}

Main File

Uses the functions:

// main.cpp
#include <iostream>
#include "math_utils.h"

using namespace std;

int main() {
    cout << add(5, 3) << endl;       // 8
    cout << multiply(4, 7) << endl;  // 28
    return 0;
}

Compilation

g++ -c math_utils.cpp -o math_utils.o
g++ -c main.cpp -o main.o
g++ math_utils.o main.o -o program
# Or all at once:
g++ math_utils.cpp main.cpp -o program

Default Arguments

Provide default values for parameters:

Syntax

// Declaration with defaults
void greet(string name = "Guest", int times = 1);

// Definition (defaults only in declaration OR definition, not both)
void greet(string name, int times) {
    for (int i = 0; i < times; i++) {
        cout << "Hello, " << name << "!" << endl;
    }
}

Usage

int main() {
    greet();               // Hello, Guest! (uses both defaults)
    greet("Alice");        // Hello, Alice! (uses times default)
    greet("Bob", 3);       // Hello, Bob! (3 times, no defaults)

    return 0;
}

Rules for Default Arguments

  1. Right-to-left: Defaults must be rightmost parameters
  2. No gaps: Can't skip parameters when calling
  3. Declare once: Either in declaration or definition
// Correct
void func(int a, int b = 5, int c = 10);

// WRONG - default before non-default
// void func(int a = 1, int b, int c = 10);

// WRONG - gap in defaults
// void func(int a, int b = 5, int c);

Function Best Practices

1. Single Responsibility

Each function should do one thing well:

// Bad - too many responsibilities
void processUserData(User& user) {
    validateEmail(user.email);
    hashPassword(user.password);
    saveToDatabase(user);
    sendWelcomeEmail(user);
}

// Good - single responsibility
void validateUser(User& user);
void securePassword(User& user);
void saveUser(User& user);
void notifyUser(User& user);

2. Descriptive Names

// Bad
int c(int a, int b);
void p(string s);

// Good
int calculateSum(int first, int second);
void printMessage(string message);

3. Keep Functions Short

Aim for 20-30 lines maximum. If longer, consider breaking into smaller functions.

4. Limit Parameters

// Bad - too many parameters
void createUser(string first, string last, string email,
                int age, string address, string city,
                string country, string phone);

// Good - use a struct/class
struct UserInfo {
    string firstName, lastName, email;
    int age;
    Address address;
    string phone;
};

void createUser(const UserInfo& info);

5. Consistent Naming Conventions

StyleExampleUse Case
camelCasecalculateTotal()Member functions
snake_casecalculate_total()Free functions
PascalCaseCalculateTotal()Some teams prefer this

6. Document Complex Functions

/**
 * Calculates the factorial of a non-negative integer.
 *
 * @param n Non-negative integer (0 to 12 for int result)
 * @return n! (factorial of n)
 * @throws invalid_argument if n is negative
 * @note Returns 1 for n=0 (0! = 1 by definition)
 */
int factorial(int n);

Summary

Key Concepts

  1. Functions encapsulate reusable code blocks
  2. Declaration specifies interface (prototype)
  3. Definition provides implementation
  4. Parameters pass data into functions
  5. Return values pass data out of functions
  6. Scope determines variable visibility
  7. Header files organize declarations

Function Syntax Quick Reference

// Declaration
returnType functionName(paramType1 param1, paramType2 param2);

// Definition
returnType functionName(paramType1 param1, paramType2 param2) {
    // body
    return value;  // if not void
}

// void function
void functionName() {
    // body
    // no return needed (or use: return;)
}

// Default arguments
void func(int a, int b = 10, int c = 20);

// auto return type (C++14)
auto func(int a, int b) {
    return a + b;
}

Common Patterns

// Getter function
int getValue() { return value; }

// Setter function
void setValue(int v) { value = v; }

// Predicate function (returns bool)
bool isEmpty() { return size == 0; }

// Factory function
Object createObject(params) { return Object(params); }

// Utility/Helper function
string formatCurrency(double amount) {
    return "$" + to_string(amount);
}

Practice Files

  • examples.cpp: Comprehensive code examples demonstrating all function concepts
  • exercises.cpp: Practice problems from beginner to advanced

Compilation

g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
g++ -std=c++17 -Wall -Wextra exercises.cpp -o exercises
./examples
./exercises
README - C++ Tutorial | DeepML