Search⌘ K
AI Features

Defining and Calling Functions

Explore defining and invoking functions in C++ to organize code into reusable, modular blocks. Understand function anatomy, parameters, return values, and the role of functions in simplifying program logic and improving maintainability.

At this stage, our programs are capable of performing meaningful work; however, they are also at risk of becoming large and difficult to maintain if all logic is placed within a single main() function. As program complexity increases, organizing code within one block quickly becomes impractical. To develop robust and maintainable applications, it is necessary to decompose large problems into smaller, well-defined units. In C++, this is accomplished through the use of functions.

Functions enable us to encapsulate specific behavior, reuse logic without duplication, and structure programs into clear, named operations. In this lesson, we move beyond monolithic code and begin constructing programs using modular building blocks.

The anatomy of a function

A function is a named sequence of statements that performs a specific task. Every function in C++ has four main components: a name, a parameter list, a body, and a return type.

The syntax follows this pattern:

ReturnType FunctionName(ParameterList) {
// Function body
// Statements...
}
  • ReturnType: The data type of the value the function sends back to the main function (e.g., int, double, std::string). If the function performs an action but does not return any value, we use void.

  • FunctionName: A unique identifier used to call the function. We use verbs or verb phrases (like calculateTotal or printMessage) to clearly indicate what the function does.

  • ParameterList: A comma-separated list of variables (inputs) declared inside the parentheses. These act as placeholders for data passed into the function. If no inputs are needed, the parentheses remain empty.

  • Function body: The block of code enclosed in braces {} that executes when the function is called.

Defining and how to call a function in C++

Let’s start with a simple function that performs an action, such as printing to the console, without returning a value. To use this logic, you need to know how to call a function in C++ once it has been defined.

C++ 23
#include <iostream>
// Definition of a function named 'greet'
// It returns nothing (void) and takes no parameters ()
void greet() {
std::cout << "Hello! Welcome to modular C++." << std::endl;
}
int main() {
std::cout << "Starting program..." << std::endl;
// This is how to call a function in C++
// You use the function name followed by parentheses
greet();
std::cout << "Back in main." << std::endl;
return 0;
}

Syntax: How to call a function in C++
To trigger a function, use the following syntax:
FunctionName(Arguments);

  • FunctionName: The exact name used in the definition.

  • Arguments: Any data the function needs (passed inside the parentheses). If the function takes no parameters, the parentheses must be empty ().

Let’s understand this step by step:

  • Line 5: We define the function's interface. void signals that this function performs a task but does not produce data to be used later.

  • Line 13: This is the execution step. To understand how to call a function in C++, notice we simply use the name greet followed by (). When the program reaches this line, it pauses main, jumps to the greet block, and resumes only after the function finishes.

Visualizing control flow transfer during a function call
Visualizing control flow transfer during a function call

Passing data with parameters

Functions become powerful when they can process different data each time they run. We achieve this using parameters. Parameters are variables defined in the function declaration that receive values when the function is called.

When we call a function, we provide concrete values called arguments. The compiler copies the value of the argument into the corresponding parameter variable.

C++ 23
#include <iostream>
// Function taking one integer parameter
void printSquare(int number) {
int square = number * number;
std::cout << "The square of " << number << " is " << square << std::endl;
}
int main() {
printSquare(5); // Argument is the literal 5
int myValue = 10;
printSquare(myValue); // Argument is the variable myValue
return 0;
}

Let’s understand this step by step:

  • Line 4: We declare int number as a placeholder (parameter). This makes the function flexible; instead of printing the square of a specific number, it can now print the square of any integer we give it.

  • Line 5: The variable number is local to this function. It is created the moment the function is called and destroyed when the function ends, ensuring it doesn't interfere with variables in main.

  • Line 10: We pass the literal value 5. The function creates a copy of this value to use as number inside its logic.

  • Line 13: Here we demonstrate that the source of the data doesn't matter. The function receives a copy of the value stored in myValue (10), allowing us to reuse the same logic for variables as well as literals.

We'll cover more on parameters in later lessons.

Returning values

Often, we need a function to perform a calculation and send the result back to the caller so it can be stored or used in further expressions. We do this using the return statement.

When a function has a non-void return type, it must execute a return statement that provides a value matching (or convertible to) that type.

C++ 23
#include <iostream>
// Function returning an integer
int add(int a, int b) {
int sum = a + b;
return sum; // Sends the value of 'sum' back to the caller
}
int main() {
// We can store the result in a variable
int result = add(3, 7);
std::cout << "3 + 7 = " << result << std::endl;
// Or use the function call directly in an expression
std::cout << "10 + 20 = " << add(10, 20) << std::endl;
return 0;
}

Let’s break this down step by step:

  • Line 4: The int at the start is a promise to the compiler that this function will calculate and produce a single integer value that replaces the function call itself.

  • Line 6: The return statement is the exit point. It stops the function immediately and ejects the value of sum back to the caller. Without this, the calculated data would be lost when the function ends.

  • Line 11: The function call add(3, 7) executes and is effectively replaced by its result (10). We capture this result in the variable result for later use.

  • Line 15: We don't always need to store the return value. Here, the result (30) is handed directly to std::cout to be printed, after which the value is discarded.

How to get a random number in C++ using a function

A practical example of using functions is generating dynamic data. Here is how to get a random number in C++ by wrapping the logic inside a reusable function.

C++ 23
#include <iostream>
#include <random> // Required for random numbers
// Function that returns a random integer between 1 and 100
int getRandomNumber() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distr(1, 100);
// This is how to get a random number in C++
return distr(gen);
}
int main() {
int myRandom = getRandomNumber();
std::cout << "Your random number is: " << myRandom << std::endl;
return 0;
}

We have transformed our ability to write code by moving logic into reusable functions. We can now define operations that accept inputs, perform specific tasks, and return results, allowing main() to act as a high-level orchestrator rather than a cluttered list of instructions. We will explore scope and lifetime in depth in the next lesson, but for now, remember that functions communicate primarily through arguments (inputs) and return values (outputs), keeping their internal logic isolated.