Department of Engineering

IT Services

7. Functions

department image Computer programs that solve real-world problems are usually much larger than the simple programs discussed so far. To design, implement and maintain larger programs it is necessary to break them down into smaller, more manageable pieces or modules. Dividing the problem into parts and building the solution from simpler parts is a key concept in problem solving and programming.

In C++ we can subdivide the functional features of a program into blocks of code known as functions. In effect these are subprograms that can be used to avoid the repetition of similar code and allow complicated tasks to be broken down into parts, making the program modular.

Until now you have encountered programs where all the code (statements) has been written inside a single function called main(). Every executable C++ program has at least this function. In the next sections we will learn how to write additional functions.

Function definition

Each function has its own name, and when that name is encountered in a program (the function call) execution of the program branches to the body of that function. After the last statement of the function has been processed (the return statement), execution resumes on the next line after the call to the function.

Functions consist of a header and a body. The header includes the name of the function and tells us (and the compiler) what type of data it expects to receive (the parameters) and the type of data it will return (return value type) to the calling function or program.

The body of the function contains the instructions to be executed. If the function returns a value, it will end with a return statement. The following is a formal description of the syntax for defining a function:

   return-value-type function-name( parameter-list )
   {
        declaration of local variables;
        statements;

        return return-value;
   }

The syntax is very similar to that of the main program, which is also a function. main() has no parameters and returns the integer 0 if the program executes correctly. Hence the return value type of the main() function is int.

    int main()
   {
       declarations;
       statements;

       return 0;
   }  

Example of function definition, declaration and call

Let us first look at an example of a program written entirely with the function main() and then we will modify it to use an additional function call.

We illustrate this with a program to calculate the factorial (n!) of an integer number (n) using a for loop to compute:

n! = 1 x 2 x 3...(n-2) x (n-1) x n

// MainFactorial.cc
// Program to calculate factorial of a number

#include <iostream>
using namespace std;

int main()
{
   int i, number=0, factorial=1;

   // User input must be an integer number between 1 and 10
   while(number<1 || number>10)
   {
     cout << "Enter integer number (1-10) = ";
     cin >> number;
   }

   // Calculate the factorial with a FOR loop
   for(i=1; i<=number; i++)
   {
      factorial = factorial*i;
   }

   // Output result
   cout << "Factorial = " << factorial << endl;
   return 0;
}

Even though the program is very short, the code to calculate the factorial is best placed inside a function since it is likely to be executed many times in the same program or in different programs (e.g. calculating the factorials of many different numbers, computing binomial coefficients and permutations and combinations).

// FunctionFactorial.cc
// Program to calculate factorial of a number with function call

#include <iostream>
using namespace std;

// Function declaration (prototype)
int Factorial(int M); 

int main()
{
   int number=0, result;

   // User input must be an integer number between 1 and 10
   while(number<1 || number>10)
   {
     cout << "Integer number = ";
     cin >> number;
   }

   // Function call and assignment of return value to result
   result = Factorial(number);  

   //Output result
   cout << "Factorial = " << result << endl;
   return 0;
}


// Function definition (header and body)
// An integer, M, is passed from caller function.
int Factorial(int M)
{
   int i, factorial=1;

   // Calculate the factorial with a FOR loop
   for(i=1; i<=M; i++)
   {
      factorial = factorial*i;
   }

   return factorial; // This value is returned to caller
}

Three modifications to the program have been made to incorporate a function. If we look at the modified sample program, FunctionFactorial.cc, we find:

  1. The declaration of the function above the main program. The declaration (also known as the prototype) tells the compiler about the function and the type of data it requires and will return on completion.
  2. The function call in the main body of the program determines when to branch to the function and how to return the value of the data computed back to the main program.
  3. The definition of the function Factorial() below the main program. The definition consists of a header which specifies how the function will interface with the main program and a body which lists the statements to be executed when the function is called.

Before a function can be used it must be declared (0), usually at the top of the program file. When the function name is encountered in the main body of the program (1), execution branches to the body of the function definition (2). Copies of the values of function arguments are stored in the memory locations allocated to the parameters. The statements of the function are then executed (3) up to the first return statement when control returns to the main body (4). Any value returned by the function is stored by an assignment statement. Execution in the main body is resumed immediately after the function call (5).

Function header and body

The function is defined below the body of main(). The header in this example:

   int Factorial(int M)

indicates that the Factorial() function expects to be passed an integer value (the parameter type) from the main body of the program and that the value passed will be stored locally in a variable named M (the formal parameter name). The return value type of the function is also int in this example, indicating that at the end of executing the body of the function, an integer value will be returned to the statement in which the function was called. Functions which do not return a value have return value type void.

The body of the function computes the factorial of a number in exactly the same way as in the example with only a main() function. The execution of the function terminates with a return statement:

   return factorial;

which specifies that the value stored in the function variable factorial should be passed back to the calling function.

Function declaration

Every function has to be declared before it is used. The declaration tells the compiler the name, return value type and parameter types of the function. In this example the declaration:

   int Factorial(int M);

tells the compiler that the program passes the value of an integer to the function and that the return value must be assigned to an integer variable. The declaration of a function is called its prototype, which means the ``first'' time the function is identified to your program.

The function prototype and the function definition must agree exactly about the return value type, function name and the parameter types. The function prototype is usually a copy of the function header followed by a semicolon to make it a declaration and placed before the main program in the program file.

Function call and execution

The function definition is entirely passive. By itself it does nothing unless instructed to execute. This is done by a statement in the main program called the function call.

For example the statement:

   result = Factorial(number);

calls the function Factorial() and passes a copy of the value stored in the variable, number. When the function is called, computer memory is allocated for the parameter, M and the value passed is copied to this memory location. Memory is also allocated to the (local) variables factorial and i. The statements of the function are then executed and assign a value to the variable factorial. The return statement passes this value back to the calling function. The memory allocated to the parameters and local variables is then destroyed. The value returned is assigned to the variable on the left-hand side, result, in the expression used to call the function. The net effect of executing the function in our example is that the variable result has been assigned the value of the factorial of number.

A function can be called any number of times from the same or different parts of the program. It can be called with different parameter values (though they must be of the correct type).

For example the following fragment of code can be used to print out the factorials of the first 10 integers:

   for(i=1; i<=10; i++)
   {
      result = Factorial(i);     
      cout << i << "! = " << result << endl;
   }

and:

   binomialCoefficient = Factorial(n)/(Factorial(k) * Factorial(n-k));

can be used to compute the binomial coefficient: n factorial divided by k factorial times open brackets n minus k close brackets factorial

Function arguments

The names of variables in the statement calling the function will not in general be the same as the names in the function definition, although they must be of the same type. We often distinguish between the formal parameters in the function definition (e.g. M) and the actual parameters for the values of the variables passed to the function (e.g. number in the example above) when it is called.

Function arguments (actual parameters) can include constants and mathematical expressions. For example the following statement assigns the value 24 to the variable result.

   result = Factorial(4);

The function arguments can also be functions that return a value, although this makes the code difficult to read and debug.

Another example

The following is another example of the declaration, definition and call of a function, AreaTriangle(), in a program to calculate the area of a regular hexagon inscribed in a circle of radius input by the user.

// HexagonValue.cc
// Program to calculate the area of a regular hexagon inscribed in a
// circle as sum of areas of 6 triangles by calling AreaTriangle()

#include <iostream>
using namespace std;

// AreaTriangle function prototype
float AreaTriangle(float base, float height); 

int main()
{
   float side, segmentHeight, hexagonArea;
   float cosTheta = 0.866025;

   cout << "Program to calculate the area of a hexagon" << endl;
   cout << "Enter side of hexagon: ";
   cin >> side;

   // Base of triangle is equal to side, height is side*cos(30)
   segmentHeight = side*cosTheta;

   // Function returns area of segment. 6 segments for total area.
   hexagonArea =  6.0 * AreaTriangle(side,segmentHeight);

   cout << "Area of hexagon = " << hexagonArea << endl;
   return 0;
}

// AreaTriangle function definition
float AreaTriangle(float base, float height)
{
   float area;
        
   area = (base*height)/2.0;
   return area;
}

The statement:

   hexagonArea =  6.0 * AreaTriangle(side,segmentHeight);

calls the function to calculate the area of a triangle with base and height given by the values stored in side and segmentHeight and then assigns the value of 6 times the area (the return value of the function) to the variable hexagonArea. It is therefore equivalent to the following:


   segmentArea = AreaTriangle(side,segmentHeight);
   hexagonArea = 6.0*segmentArea;

Passing by value or reference

There are two ways to pass values to functions. Up to now we have only looked at examples of passing by value. In the passing by value way of passing parameters, a copy of the variable is made and passed to the function. Changes to that copy do not affect the original variable's value in the calling function. This prevents the accidental corrupting of variables by functions and so is the preferred method for developing correct and reliable software systems.

One disadvantage of passing by value however, is that only a single value can be returned to the caller. If the function has to modify the value of an argument or has to return more than one value, then another method is required.

An alternative uses passing by reference in which the function is told where in memory the data is stored (i.e. the function is passed the memory address of the variables). In passing the address of the variable we allow the function to not only read the value stored but also to change it. On the other hand, by passing the value by name we simply let the function know what the value is.

To indicate that a function parameter is passed by reference the symbol & is placed next to the variable name in the parameter list of the function definition and prototype (but not the function call). Inside the function the variable is treated like any other variable. Any changes made to it, however, will automatically result in changes in the value of the variable in the calling function.

Passing by reference is an advanced topic in C++. What is really being passed is a pointer to the memory address of the variable. The symbol & is called the address of operator and the parameter value becomes the address of the variable following it.

The use of pointers in C++ is a powerful feature of the language, but is probably one of the most difficult to understand. The preferred way of passing arguments to a function is by passing by value calls. This is sufficient for the simple programs considered in this course in which only a single value has to be returned to the calling function. However, if the function has to modify the value of an argument or has to return more than one value, then this must be done by passing by reference.

A simple example of passing by reference is given below for a function which swaps the values of two variables in the calling function's data by reading and writing to the memory locations of these variables. Note that the parameters are mentioned only by name in the function call. This appears to be the same as calling by value. The function header and prototype, however, must use the & symbol by the variable name to indicate that the call is by reference and that the function can change the variable values.

// SortReference.cc
// Program to sort two numbers using call by reference. 
// Smallest number is output first.

#include <iostream>

using namespace std;

// Function prototype for call by reference
void swap(float &x, float &y);

int main()
{
   float a, b;
   
   cout << "Enter 2 numbers: " << endl;
   cin >> a >> b;
   if(a>b) 
     swap(a,b);

   // Variable a contains value of smallest number
   cout << "Sorted numbers: ";
   cout << a << " " << b << endl;
   return 0;
}

// A function definition for call by reference
// The variables x and y will have their values changed.


void swap(float &x, float &y)
// Swaps x and y data of calling function
{
   float temp;

   temp = x;
   x = y;
   y = temp;
}

Back to top