Page Content

Tutorials

What Is Mean By Functions In C++ With Examples?

Functions in C++

As a designated block of code intended to carry out a particular purpose, a function is a basic unit of computation in C++. By enabling programs to be broken down into smaller, modular components, functions facilitate the efficient development of software. This modularity makes the code easier to comprehend and reuse, and it makes debugging and maintenance easier. An essential starting point where a C++ program starts to run is the main() function, which plays a unique role.

Defining Functions

C++ function definitions typically include the function body, parameter list (which may be empty), name, and return type.

Syntax

return_type function_name(parameter_type1, parameter_type2, ...); 

Function Declaration (Prototype) and Definition:

  • Before it can be utilised, a function needs to be declared.
  • Name, return type, and parameter types are among the key details that a function declaration, sometimes referred to as a function prototype, gives the compiler about the function. As a result, when the function is invoked, the compiler can check for type errors. Only the types of parameters are absolutely necessary in a prototype; parameter names are not.
  • A function definition is a pair of curly brackets {} that encloses the actual code that the function runs. A function can have more than one declaration, but it must be defined exactly once.
  • Functions are usually defined in distinct source files and declared in header files in large programs to allow for independent compilation.

Function Body: What the function does is defined by the block of statements called the function body. If it returns a value, a function must have at least one return statement in its body that returns the chosen return type or an implicitly convertible type. Functions that return nothing must return void.

Example

#include <iostream>
#include <string>
// --- Function Declarations (Prototypes) ---
// These tell the compiler that these functions exist and what their signatures are.
int addNumbers(int a, int b);
void greetUser(const std::string& name);
double calculateCircleArea(double radius);
// --- main function (calls functions declared above) ---
int main() {
    int sum_result = addNumbers(10, 20); // Compiler knows about addNumbers
    std::cout << "Sum: " << sum_result << std::endl;
    greetUser("Alice"); // Compiler knows about greetUser
    double area = calculateCircleArea(5.0); // Compiler knows about calculateCircleArea
    std::cout << "Area of circle with radius 5.0: " << area << std::endl;
    return 0;
}
// --- Function Definitions (Implementations) ---
// These provide the actual code for the declared functions.
int addNumbers(int a, int b) {
    return a + b;
}
void greetUser(const std::string& name) {
    std::cout << "Hello, " << name << "!\n";
}
// Defining PI here for example, often it would be a global constant or part of a math library
const double PI = 3.14159;
double calculateCircleArea(double radius) {
    return PI * radius * radius;
}

Output

Sum: 30
Hello, Alice!
Area of circle with radius 5.0: 78.5397

Calling Functions

A pair of brackets () behind the function name is the call operator, which is used to call or invoke a function. Upon calling a function, the called function immediately gains control of the program. While the called function starts to run, the calling function’s execution is momentarily halted. Control returns to the place immediately following the function call in the calling program; this happens when the called function’s closing brace or return statement is encountered.

Example: Calling a void Function with No Arguments

#include <iostream>
// Function Declaration (Prototype)
void displayMessage();
int main() {
    // Calling the function
    displayMessage();
    displayMessage(); // You can call it multiple times
    return 0;
}
// Function Definition
void displayMessage() {
    std::cout << "This is a simple message.\n";
}

Output

This is a simple message.
This is a simple message.

Function Parameters (Pass-by-Value)

In the parameter list of a function, parameters are local variables that are declared. They act as stand-ins for the actual arguments values that are passed when a function is called.

Passing by Value: For parameters, C++ functions by default employ pass-by-value. A copy of the argument’s value is created and used to initialise the relevant parameter whenever a function is called. Therefore, the original argument in the calling code remains unaffected by any changes made to the parameter inside the function’s body. When parameters are supplied by value, the function treats them the same as any other local variable.

Parameter List: Use the void keyword or leave the parameter list empty to indicate a function accepts no arguments. Even if all parameters are the same type, they must be declared separately and repeated. Although pass-by-value is the default, C++ also features pass-by-reference, which enables functions to access and alter the original parameters directly via pointers or C++ references.

Example

#include <iostream>
#include <string>
// Function Declaration
void modifyNumber(int num);
void appendText(std::string text);
int main() {
    // --- Example 1: Passing an integer by value ---
    int my_number = 10;
    std::cout << "Before calling modifyNumber: my_number = " << my_number << std::endl;
    // Call the function, passing my_number by value
    modifyNumber(my_number);
    std::cout << "After calling modifyNumber: my_number = " << my_number << std::endl;
    // Observe: my_number remains 10, because a copy was modified.
 
    return 0;
}
// Function Definition for modifyNumber (parameter 'num' is pass-by-value)
void modifyNumber(int num) {
    std::cout << "  Inside modifyNumber: Initial num = " << num << std::endl;
    num = num * 2; // Modify the local copy of num
    std::cout << "  Inside modifyNumber: Modified num = " << num << std::endl;
}

Output

Before calling modifyNumber: my_number = 10
  Inside modifyNumber: Initial num = 10
  Inside modifyNumber: Modified num = 20
After calling modifyNumber: my_number = 10

Code Example for Passing a string by value

#include <iostream>
#include <string>
// Function Declaration
void modifyNumber(int num);
void appendText(std::string text);
int main() {
std::string my_string = "Hello";
    std::cout << "Before calling appendText: my_string = \"" << my_string << "\"" << std::endl;
    // Call the function, passing my_string by value
    appendText(my_string);
    std::cout << "After calling appendText: my_string = \"" << my_string << "\"" << std::endl;
    // Observe: my_string remains "Hello", because a copy was modified.
    return 0;
}
// Function Definition for appendText (parameter 'text' is pass-by-value)
void appendText(std::string text) {
    std::cout << "  Inside appendText: Initial text = \"" << text << "\"" << std::endl;
    text += ", World!"; // Modify the local copy of text
    std::cout << "  Inside appendText: Modified text = \"" << text << "\"" << std::endl;
}

Output

Before calling appendText: my_string = "Hello"
  Inside appendText: Initial text = "Hello"
  Inside appendText: Modified text = "Hello, World!"
After calling appendText: my_string = "Hello"

Function Signature

The function signature, which is required in function declarations, contains the function name and parameter types. The return type is notably not regarded as a component of the function’s signature when overloading. The compiler uses the function signature to choose the correct function depending on the parameters supplied in the call and to resolve calls to overloaded functions functions with the same name but different parameter lists.

Inline Functions

An inline function is a compiler optimisation method that is mostly used to minimise function call overhead, especially for short functions that are called often.

Compiler Suggestion: The inline keyword tells the compiler to substitute the function’s code “in line” at each invocation instead of jumping to a different subroutine. If the function is too large or sophisticated to inline, the compiler may ignore this request.

Benefits and Drawbacks: By removing the need to create a new stack frame for every function call, inlining can potentially speed up the execution of short functions. It may even reduce the overall code size for very small routines. For longer routines, on the other hand, inlining could result in “code bloat,” which is the result of duplicate code making the executable file larger.

Definition Requirement: In order for a function to be inlined, the compiler must have access to the function’s whole definition at the time of call, including the function body. Since ordinary functions are frequently stated in headers and defined in separate source files, inline functions are usually defined directly within header files.

Class Member Functions: Despite not using the inline keyword explicitly, member functions defined right inside a class declaration are inherently inline.

Restrictions: Certain functions, such as those using loops, switch statements, goto statements, static variables, or recursive calls, may not experience inline expansion. In C++, inline functions are frequently used over preprocessor macros because of their type-safe nature.

Example

#include <iostream>
// Function definition for a non-inline function
int addNumbers(int a, int b) {
    return a + b;
}
// Inline function definition
// The 'inline' keyword is a suggestion to the compiler
inline int multiplyNumbers(int x, int y) {
    return x * y;
}
// Another inline function for a simple comparison
inline bool isEven(int n) {
    return (n % 2 == 0);
}
int main() {
    int num1 = 5;
    int num2 = 10;
    int num3 = 7;
    std::cout << "--- Demonstrating Inline Functions ---" << std::endl;
    // Calling the non-inline function
    int sum = addNumbers(num1, num2);
    std::cout << "Sum: " << sum << std::endl; // Normal function call overhead
    // Calling the inline function (compiler may expand its code here)
    int product = multiplyNumbers(num1, num2);
    std::cout << "Product: " << product << std::endl; // Potential inlining
    // Calling another inline function
    if (isEven(num2)) {
        std::cout << num2 << " is an even number." << std::endl; // Potential inlining
    }
    if (!isEven(num3)) {
        std::cout << num3 << " is an odd number." << std::endl; // Potential inlining
    }
    // Using inline function directly in an expression
    int result_expression = 100 + multiplyNumbers(3, 4);
    std::cout << "Expression result (100 + 3*4): " << result_expression << std::endl;

    std::cout << "\n--- Impact on Code Size and Performance ---" << std::endl;
    std::cout << "For very small functions like multiplyNumbers or isEven, "
              << "inlining might reduce call overhead.\n";
    std::cout << "For larger functions (like addNumbers if it had many lines), "
              << "inlining could lead to 'code bloat' and slower performance.\n";
    std::cout << "The compiler ultimately decides whether to inline or not.\n";
    return 0;
}

Output

--- Demonstrating Inline Functions ---
Sum: 15
Product: 50
10 is an even number.
7 is an odd number.
Expression result (100 + 3*4): 112
--- Impact on Code Size and Performance ---
For very small functions like multiplyNumbers or isEven, inlining might reduce call overhead.
For larger functions (like addNumbers if it had many lines), inlining could lead to 'code bloat' and slower performance.
The compiler ultimately decides whether to inline or not.

You can also read What Are C Functions And It’s Types With Code Examples?

Function Scope

The scope of a C++ program determines the area of the text where a name (such the name of a variable or function) is accessible and visible. A function’s declared variables and parameters are expressly referred to as its scope.

Local Variables: Local variables are defined within the body of a function, such as its parameters. Only within the block of their defining function are these variables visible and present, making them local to that particular function. They are formed when the function is entered and deleted when it exits, therefore unless the static storage class specifier is used, their values are not retained across function runs. An entity with the same name that has been defined in an outer scope can also be hidden by local declarations.

No Nested Functions: The ability to define a function inside another function is not supported by C++.

Global Variables: With global scope, variables declared outside of any function are visible and accessible to all functions during the execution of the program and maintain their values for the duration of the program.

Call Stack and Memory: A stack frame for the function’s parameters and local variables is created up in memory by the compiler each time it is called. Both the generation and cleanup of the stack frame come with a memory and performance cost.

You can also read What Are The Jump statements In C++ With Code Examples?

Agarapu Geetha
Agarapu Geetha
My name is Agarapu Geetha, a B.Com graduate with a strong passion for technology and innovation. I work as a content writer at Govindhtech, where I dedicate myself to exploring and publishing the latest updates in the world of tech.
Index