FUNCTIONS IN THE C++ PROGRAMMING LANGUAGE

Lesson Content: Functions in C++

Welcome to the lesson on functions in the C++ language! Functions are the fundamental building blocks of any program, allowing code to be organized into smaller, easily understandable parts. In this lesson, we will explain how functions work, how to define and use them, and what their advantages are. We will cover different types of functions, including functions with and without return values, functions with parameters, function overloading, and recursion.

Programs written in the C++ programming language can contain a large number of statements, and if they were written one after another in a single file, developers would have difficulty navigating such code, making it hard to maintain. On the other hand, it often happens that a single algorithm, a set of statements that solve a small or large problem within an application, is repeated multiple times.

It can be concluded that it would be much better to extract that set of statements (part of the program) as a single unit, once as a subprogram or function, and then call that function whenever needed. Subprograms are a mechanism for breaking down complex problems into subproblems.

The C programming language recognizes only one type of subprogram, which is called a function.

You can find examples of functions on the following web page: Functions in C/C++ - Examples

There are three key aspects to understand about functions:

  • Function Declaration
  • Function Definition
  • Function Call

Function Declaration



The function declaration (also known as the function prototype) is a way to inform the compiler in advance about the existence of a function, its return type, and its arguments. This is useful when the function is not implemented before its call in the code.

In programming, a declaration of a variable or function refers to defining its identifier and describing its properties without allocating memory space for storing the data or function. In the case of a function, the declaration specifies the return type and the number and types of arguments. In general, the declaration looks like this:

return_type function_name(argument_list);


The function declaration is also known as a function prototype or a function signature.

If the function is located in the file above the main function, as in the previous examples, then a separate declaration is not required. Otherwise, the declaration must be written above the main function. For example, the prototype of the max function would be:



int max(int a, int b);


or simply


int max(int, int);


The function prototype of promeni_ref looks like this:


void promeni_ref(int *);


Example Code with Function Declaration


#include <iostream>
using namespacestd;

// Function declaration that calculates the sum of two numbers
int sum(int a, int b);

int main() {
int result = sum(5, 7); // Calling the sum function with arguments 5 and 7
cout << "The sum is: " << result << endl;
return 0; // End of program
}

// Definition of the sum function that returns the sum of two numbers
int sum(int a, int b) {
return a + b; // Returns the sum of the given numbers
}

Defining functions



The function definition contains the actual implementation of the function, i.e. her body. It states what the function should do when called.

Example of a function definition

Product function: This function takes two parameters (x and y), and returns their product.
// Definition of a function that calculates the product of two numbers
int product(int x, int y) {
return x * y; // The function returns the product of x and y
}
Defining a function means that we write the commands that make up the function and that should determine a specific task in an application (program) somewhere in the program, group them in some way, give a name and determine what data should be submitted to the function as input parameters and what data the function returns as a return value. Therefore, defining the function should include:

Example 1: Finding the maximum of two integers



Task: Create a function that determines the maximum of two integers. Test this call inside the main function.This can be seen in the following figure. The method (function) for calculating the maximum between two integers is shown:​Defining a function (method)
Figure 1: Defining a function (method)

In the method header, there are two words.

The first one, in this case, int, represents the data type of the return value. This method, which calculates the larger number between two integers, returns that number, whose type is int. This is the return type.

The second word is the method name, which is chosen by the programmer and should suggest the purpose of the method.

The method body is enclosed in curly braces. Inside the body, the function’s statements are written.

In the function (method) header, after the name, the function parameters (arguments) are placed inside parentheses. These are the data that need to be provided to the function so it can complete the given task.

In the previous example, the task of the function is to determine the maximum between two integers, and the data that needs to be provided to the function via parameters are those two numbers, in this case, denoted as a and b.

The following image provides a more detailed view of this method.

Defining the function-details
Figure 2: Defining the function-details

A function can have zero, one, or multiple parameters. If a function does not require input data, the parentheses in the function header will remain empty.

If a method does not return a value, it will not have a return statement with data in its body, but it may contain just return. In such cases, the return type is specified as void.

A program must have at least one function, which is the main (main) function. An example of the main function from the previous example is shown in the image below.

Determining the maximum of two integer-main functions
Figure 3: Determining the maximum of two integer-main functions

Inside the main function, two integer numbers are first read, and then the maximum is determined. The statements that determine the maximum are separated into a special method called max (see image 2).

In the main function, the cout statement is used to print this value. At the place where the data for printing is expected, there is a call to the max function. The values A and B are passed as parameters, which are actually copies of these values.

The max function determines the larger value and returns it as a return value. This return value will be printed together with the text "The larger number is" in the output.

After running the program and entering the values, for example, 5 and 10 for A and B, the output will be:

Determination of max two integers-output
Figure 4: Determination of max two integers-output

Function call



A function call is the process where a function is invoked to perform its logic and return a result (if any). Functions can be called:

​An example of a function call in main():

#include <iostream>
using namespace std;

// Declaration of a function that calculates the square of a number
int square(int number);

int main() {
int number = 4;
cout << "The square of " << number << " is: " << square(number) << endl;
return 0;
}

// Definition of a function that calculates the square of a number
int square(int number) {
return number * number;
}
Explanation:
​

Calling functions inside other functions:​

#include <iostream>
using namespacestd;

// Function declarations
int sum(int a, int b);
int square_of_sum(int a, int b);

int main() {
int result = square_of_sum(3, 4);
cout << "The square of the sum is: " << result << endl;
return 0;
}

// Definition of a function that calculates the sum of two numbers
int sum(int a, int b) {
return a + b;
}

// Definition of a function that calculates the square of the sum of two numbers
int square_of_sum(int a, int b) {
int s = sum(a, b); // Calling the sum function inside square_of_sum
return s * s;
}
Explanation:

Test your code in the editor below!

// Write your C++ code here...

More detailed explanation of function calls in the example "Determining the maximum of two numbers". Continuation of the task.

The only function that is automatically called when the application starts is the main function. The commands in main are executed in order from top to bottom, and when the last command is finished, the program ends. If there are other functions defined in the project, they will not execute on their own. In order for the program to continue execution in another function from main, one of the commands in main must be a call to another function.

In the example shown in image 3, the max function is called:

cout << "The greater number is " << max(A, B);

The declaration of a function call generally looks like this:

function_name(parameter1, parameter2, ...);

The parameters passed to the function are copied in order into the parameters defined in the function definition (see image 2). In the function definition, the data type is placed in front of the parameter name:

int max(int a, int b)

Here, new memory is actually reserved labeled as a and b, which takes the copies of the parameter values from the function call:

max(A, B);

The data type is not specified before the parameter in the function call. The copying of parameters is shown in image 5.
Passing parameters to the function max-schematic view
Figure 5: Passing parameters to the function max-schematic view

Example 1-continued: Subtracting the maximum of two numbers-code​

Task: Create a function that determines the maximum of two integers that are passed as function parameters.
Load two integers and determine their maximum using the previously defined function.
#include <iostream>
using namespace std;

// Function that determines the maximum between two numbers
intmax(int a, int b) {
if (a > b) {
returna; // If a is greater, return a as the maximum
} else {
returnb; // Otherwise, return b as the maximum
}
}

intmain() {
int number1, number2;
cout << "Enter the first number: ";
cin >> number1;
cout << "Enter the second number: ";
cin >> number2;

cout << "The greater number is: " << max(number1, number2) << endl;

return 0; // End of the program
}

Passing a parameter by value and by reference



The previous example shows passing a parameter by value. Since the parameters in the second function represent a new memory that only receives copies of values ​​from the memory of the parameters of the main function, any possible change of value within the second function will not affect the data defined in the first one.
We can illustrate this through the following example:

Example 2: Substitution of data value



Set an integer value to 20, then create a method that changes this value to 100.
Let's create a function that will change the value of the sent data:Example of
Figure 6: Example of "substitution of value to data" - by value
When we run this program, we get the output:Example
Figure 7: Example "Substitution of value to data" - output
We can see that in the main function this value has not been changed and if at first glance everything seems to be correct in the code.
This value did change inside the change_vr function, but this change is not reflected in the data in the main function.
For this to be correct, the parameters must be passed by reference.

Passing function parameters by reference



Unlike passing by value, when passing by reference, no new memory is created for the parameters in the second function "change_ref". Instead, these parameters are actually references (another name) to the same memory that is occupied by the data parameters in the main function. This will cause any changes to the parameter values in the second function to reflect back on the first one. Let's modify the previous example by replacing the function that now passes parameters by reference. The parameters are no longer data but pointers to that data. More about pointers can be found in the lesson Pointers in C++.
Parameters are now not data but data references. The previous example now looks:
#include <iostream>
using namespace std;

// Function to change value by reference
void change_ref(int& a) {
a = 200;
cout << "Function change_ref, a=" << a << endl;
}

intmain() {
int a;
cin >> a;
cout << "a=" << a << endl;
change_ref(a);
cout << "After change: a=" << a << endl;
return 0;
}
After starting the application:
Enter a value: 10
a=10
Function change_ref, a=200
After change: a=200

Function Parameter Passing by Pointer



Instead of references, pointers to data can also be used. The effect is similar to passing by reference, meaning that changes made inside the function to the data accessed through the pointer will reflect on the original data defined in the main function. This happens because pointers point to the original data, not to a new one that just has the same value as the original.

More about pointers can be found in the Pointers in C++ lesson.


Code Example:



#include <iostream> // Including the input-output library
using namespace std; // Using the std namespace

/*
        void change_value(int pr){
            pr = 200; // This function does not change the original variable because the parameter is passed by value
        }
*/

void change_by_pointer(int *pr){ // Function takes a pointer to int
*pr = 200; // Changing the value at the address the pointer is pointing to
cout << "In function: " << (*pr) << endl; // Displaying the new value in the function
}

int main() { // Main function of the program
int x; // Declaring variable x
x = 30; // Setting the initial value
cout << x << endl; // Displaying the original value
// change_value(x); // This call would leave x unchanged
change_by_pointer(&x); // Passing the address of x to the function
cout << x << endl; // Displaying the new value of x after the function call
return0; // End of the program
}


Output:

30
In function: 200
200

Examples of Functions with Different Return Types and Arguments



1. Function with no return value (void)

Functions that do not return a value use the return type void. They are used for performing actions, such as printing output to the screen.

Example:

void greet() {
cout << "Welcome to the world of programming!" << endl;
}

int main() {
greet(); // Function call
return0;
}

Explanation:

  • The greet function does not return a value because it uses the return type void.
  • It performs only one action - printing a message.

2. Function with return type int

The function can return numerical values that are used in the further course of the program.

Code:

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

int main() {
int result = sum(5, 7); // Function call
cout << "The sum is: " << result << endl;

return0;
}

Explanation:

  • The sum function takes two arguments (a and b) and returns their sum as the result.

3. Function with return type double

This is used when decimal numbers are required, for example, in mathematical calculations.

Code:

double circleArea(double r) {
return3.14159 * r * r;
}

int main() {
double r = 5.0;
double area = circleArea(r);
cout << "The area of the circle is: " << area << endl;

return0;
}

Explanation:

  • The circleArea function calculates the area of a circle using the formula π · r² and returns the result as a double.

4. Function with return type string

Used for working with textual values.

Code:

string greetingMessage(string name) {
return"Hello, " + name + "!";
}

int main() {
string name = "Ana";
cout << greetingMessage(name) << endl;

return0;
}

Explanation:

  • The greetingMessage function takes a textual argument and returns a personalized message.

Recursive functions

Recursive functions are functions that call themselves, either directly or indirectly. This approach allows solving problems that can naturally be divided into smaller subproblems.

For a more detailed explanation and practical examples, visit our page: Recursive Algorithms.

Video lesson: Functions in the C++ language

​Common Mistakes and Tips



​When working with functions in C++, certain mistakes frequently occur. Here are some examples along with tips on how to avoid them:


Most Common Mistakes When Working with Functions

  • Forgotten function declaration: If a function is not declared before being called, the compiler will not recognize it.
    Tip: Always declare functions before the main function main() or use header files.
  • Argument type mismatch: Passing arguments of the wrong type can cause errors.
    Tip: Check argument types and ensure they match the function declaration.
  • Missing return value: You declared a function to return a value but forgot the return statement.
    Tip: Always verify that the function returns a value if its return type is not void.
  • Recursion without a base case: If a function lacks a condition to stop recursion, it will result in infinite calls.
    Tip: Always define a base case (termination condition) for recursive functions.

​Connecting with Object-Oriented Concepts



​​In object-oriented programming (OOP), functions play a key role as part of classes and objects:


Functions and OOP in C++

Within classes, functions are called methods. They allow objects to perform tasks and manipulate their data.

Example:

<iostream>
using namespace std;

class Circle {
private:
double radius;

public:
// Constructor to initialize the radius
Circle(double r) {
radius = r;
}

// Method to calculate the area
double area() {
return3.14 * radius * radius;
}
};

int main() {
// Creating an object
Circle c(5.0);

// Calling the method
cout << "The area of the circle is: " << c.area() << endl;

return0;
}

Methods like area() enable encapsulation of logic within classes, making the code more modular and readable.

Class Circle: Defines the private data member radius and the public method area(), which calculates the area of the circle.

Constructor: Initializes radius when creating an object.

Method area(): Returns the area of the circle using the formula π r2.

Main function: Creates an object of the Circle class, calls the area() method, and prints the result.

Function Overloading



Function overloading allows defining multiple functions with the same name but with different numbers or types of parameters. This enables more intuitive function calls with various data types.

#include<iostream>using namespacestd;

voidprint(intnumber) {
    cout << "Integer value: " << number << endl;
}

voidprint(std::stringtext) {
    cout << "String value: " << text << endl;
}

intmain() {
    print(42);
    print("Hello");
    return0;
}
  

Inline Functions

Inline functions are those that expand directly into the code instead of being called, which can improve performance for very small functions. They are defined using the inline keyword.



#include<iostream>using namespacestd;

inline intadd(inta, intb) {
    returna + b;
}

intmain() {
    intresult = add(3, 4);
    cout << "Result: " << result << endl;
    return0;
}
  


Nested Functions (Lambda Expressions)

C++ does not support nested functions in the traditional sense, but lambda expressions allow defining functions within other functions. This is often used for short operations executed within a function.


#include<iostream>using namespacestd;

intmain() {
    // Lambda function for adding two numbers
auto add = [](inta, intb) -> int {
returna + b;
};

intresult = add(10, 20);
cout << "Lambda function result: " << result << endl;

return0;
}

Explanation:
Function Overloading: In the example above, the function print is overloaded to handle both integer and string values. This allows for more flexible use of the same function with different data types.


Inline Functions: The function add is declared as inline, meaning its code is inserted directly at the call site, reducing function call overhead, which is useful for simple operations.


Nested Functions (Lambda Expressions): Although C++ does not support traditional nested functions, lambda expressions enable defining functions within functions. In the example above, the lambda function add is defined inside the main function and is used for adding two numbers.


Function Overloading



Function overloading allows defining multiple functions with the same name but with different numbers or types of parameters. This enables more intuitive function calls with various data types.

#include<iostream>using namespacestd;

voidprint(intnumber) {
    cout << "Integer value: " << broj << endl;
}

voidprint(std::stringtext) {
    cout << "String value: " << text << endl;
}

intmain() {
    print(42);
    print("Hello");
    return0;
}
  

Inline Functions

Inline functions are those that expand directly into the code instead of being called, which can improve performance for very small functions. They are defined using the inline keyword.



#include<iostream>using namespacestd;

inline intadd(inta, intb) {
    returna + b;
}

intmain() {
    intresult = add(3, 4);
    cout << "Result: " << result << endl;
    return0;
}
  


Nested Functions (Lambda Expressions)

C++ does not support nested functions in the traditional sense, but lambda expressions allow defining functions within other functions. This is often used for short operations executed within a function.


#include<iostream>using namespacestd;

intmain() {
    // Lambda function for adding two numbers
auto add = [](inta, intb) -> int {
returna + b;
};

intresult = add(10, 20);
cout << "Lambda function result: " << result << endl;

return0;
}

Explanation:
Function Overloading: In the example above, the function ispisi is overloaded to handle both integer and string values. This allows for more flexible use of the same function with different data types.


Inline Functions: The function saberi is declared as inline, meaning its code is inserted directly at the call site, reducing function call overhead, which is useful for simple operations.


Nested Functions (Lambda Expressions): Although C++ does not support traditional nested functions, lambda expressions enable defining functions within functions. In the example above, the lambda function saberi is defined inside the main function and is used for adding two numbers.


Example of Using Functions in Larger Projects

In larger projects, functions are used to organize code, improve readability, and facilitate easier maintenance. For example, let's consider a simulation of a student data management system.

Project Structure

  • main.cpp – The main file that runs the program
  • student.hpp / student.cpp – Classes and functions for working with students
  • database.hpp / database.cpp – Functions for database manipulation

Implementation

Below is a simplified example of how functions are used to organize student-related operations.

student.hpp (Student Structure Definition)

#ifndef STUDENT_HPP
#define STUDENT_HPP

#include <iostream>#include <string>struct Student {
    std::string firstName;
    std::string lastName;
    int index;

    void showData();
};

#endif

student.cpp (Method Implementation)

#include "student.hpp"void Student::showData() {
    std::cout << "Student: " << firstName << " " << lastName << ", Index: " << index << std::endl;
}

database.hpp (Function Declarations for Student Management)

#ifndef DATABASE_HPP
#define DATABASE_HPP

#include "student.hpp"#include <vector>class Database {
private:
    std::vector<Student> students;

public:
    void addStudent(const Student& s);
    void showAllStudents();
};

#endif

database.cpp (Function Implementation)

#include "database.hpp"#include <iostream>void Database::addStudent(const Student& s) {
    students.push_back(s);
}

void Database::showAllStudents() {
    for (const auto& s : students) {
        s.showData();
    }
}

main.cpp (Main Program)

#include "database.hpp"int main() {
    Database db;
    
    Student s1 = {"Marko", "Marković", 202301};
    Student s2 = {"Ana", "Anić", 202302};

    db.addStudent(s1);
    db.addStudent(s2);

    db.showAllStudents();

    return 0;
}

Explanation

  • By using separate files for different components, the code becomes modular and easier to maintain.
  • The Database class enables working with a collection of students, while individual student operations are handled through the Student class.
  • Functions help isolate specific operations, increasing code reusability.

Additional Resources


For additional questions and explanations, contact us via the contact form.


​Previous
​|< Pointers in C++