[go: up one dir, main page]

0% found this document useful (0 votes)
6 views12 pages

ch5

Chapter Five discusses the structure and usage of functions in C++, including their format, scope of variables, and different types of function calls. It covers concepts such as passing arguments by value and by reference, default values for parameters, function overloading, inline functions, and recursion. The chapter provides examples to illustrate these concepts and emphasizes the modularity and reusability that functions bring to programming.

Uploaded by

Yohanis Agumase
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views12 pages

ch5

Chapter Five discusses the structure and usage of functions in C++, including their format, scope of variables, and different types of function calls. It covers concepts such as passing arguments by value and by reference, default values for parameters, function overloading, inline functions, and recursion. The chapter provides examples to illustrate these concepts and emphasizes the modularity and reusability that functions bring to programming.

Uploaded by

Yohanis Agumase
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

Chapter Five: Function

5.1 Function format (Type, Name, Argument, Statement)

 Using functions we can structure our programs in a more modular way, accessing all
the potential that structured programming in C++ can offer us.
 A function is a block of instructions that is executed when it is called from some other
point of the program. The following is its format:

Type name (argument1, argument2 ...) statement


Where:

 Type is the type of data returned by the function.


 Name is the name by which it will be possible to call the function.
 Arguments (as many as wanted can be specified). Each argument consists of a
type of data followed by its identifier, like in a variable declaration (for
example, int x) and which acts within the function like any other variable.
They allow passing parameters to the function when it is called. The different
parameters are separated by commas.
 Statement is the function's body. It can be a single instruction or a block of
instructions. In the latter case it must be delimited by curly brackets {}.
 Here you have the first function example:

// function example The result is 8


#include <iostream.h>

int addition (int a, int b)


{
int r;
r=a+b;
return (r);
}

int main ()
{
int z;
z = addition (5,3);
cout << "The result is " << z;
return 0;
}

In order to examine this code, first of all remember something said at the beginning of
this course: a C++ program always begins its execution with the main function. So we
will begin there.

44
We can see how the main function begins by declaring the variable z of type int. Right
after that we see a call to addition function. If we pay attention we will be able to see the
similarity between the structure of the call to the function and the declaration of the
function itself in the code lines above:

The parameters have a clear correspondence. Within the main function we called to
addition passing two values: 5 and 3 that correspond to the int a and int b parameters
declared for the function addition.

At the moment at which the function is called from main, control is lost by main and
passed to function addition. The value of both parameters passed in the call (5 and 3) are
copied to the local variables int a and int b within the function.

Function addition declares a new variable (int r ;), and by means of the expression
r=a+b, it assigns to r the result of a plus b. Because the passed parameters for a and b
are 5 and 3 respectively, the result is 8.

The following line of code:

return (r);
finalizes function addition, and returns the control back to the function that called it
(main) following the program from the same point at which it was interrupted by the call
to addition. But additionally, return was called with the content of variable r (return
(r);), which at that moment was 8, so this value is said to be returned by the function.

The value returned by a function is the value given to the function when it is evaluated.
Therefore, z will store the value returned by addition (5, 3), that is 8. To explain it
another way, you can imagine that the call to a function (addition (5,3)) is literally
replaced by the value it returns (8).

The following line of code in main is:

cout << "The result is " << z;


that, as you may already suppose, produces the printing of the result on the screen.

45
Scope of variables [re]

You must consider that


the scope of variables
declared within a
function or any other
block of instructions is
only their own function
or their own block of
instructions and cannot
be used outside of them.
For example, in the
previous example it had
been impossible to use
the variables a, b or r
directly in function main
since they were local variables to function addition. Also, it had been impossible to use
the variable z directly within function addition, since this was a local variable to the
function main.

Therefore, the scope of local variables is limited to the same nesting level in which they
are declared. Nevertheless you can also declare global variables that are visible from any
point of the code, inside and outside any function. In order to declare global variables you
must do it outside any function or block of instructions that means, directly in the body of
the program.

 And here is another example about functions:

// function example The first result is 5


#include <iostream.h> The second result is 5
The third result is 2
int subtraction (int a, int b) The fourth result is 6
{
int r;
r=a-b;
return (r);
}

int main ()
{
int x=5, y=3, z;
z = subtraction (7,2);
cout << "The first result is " << z << '\n';
cout << "The second result is " <<
subtraction (7,2) << '\n';

46
cout << "The third result is " <<
subtraction (x,y) << '\n';
z= 4 + subtraction (x,y);
cout << "The fourth result is " << z <<
'\n';
return 0;
}

In this case we have created the function subtraction. The only thing that this function
does is to subtract both passed parameters and to return the result.

Nevertheless, if we examine the function main we will see that we have made several
calls to function subtraction. We have used some different calling methods so that you
see other ways or moments when a function can be called.

In order to understand well these examples you must consider once again that a call to a
function could be perfectly replaced by its return value. For example the first case (that
you should already know because it is the same pattern that we have used in previous
examples):

z = subtraction (7, 2);


cout << "The first result is” << z;
If we replace the function call by its result (that is 5), we would have:
z = 5;
cout << "The first result is " << z;

As well as

cout << "The second result is " << subtraction (7,2);


has the same result as the previous call, but in this case we made the call to subtraction
directly as a parameter for cout. Simply imagine that we had written:
cout << "The second result is” << 5;
since 5 is the result of subtraction (7, 2).

In the case of

cout << "The third result is” << subtraction (x,y);


The only new thing that we introduced is that the parameters of subtraction are variables
instead of constants. That is perfectly valid. In this case the values passed to the function
subtraction are the values of x and y, that are 5 and 3 respectively, giving 2 as result.

The fourth case is more of the same. Simply note that instead of:

z = 4 + subtraction (x, y);


We could have put:
z = subtraction (x, y) + 4;

47
With exactly the same result. Notice that the semicolon sign (;) goes at the end of the
whole expression. It does not necessarily have to go right after the function call. The
explanation might be once again that you imagine that a function can be replaced by its
result:
z = 4 + 2;
z = 2 + 4;

Functions with no types -The use of void

 If you remember the syntax of a function declaration:


Type name (argument1, argument2 ...) statement
You will see that it is obligatory that this declaration begins with a type that is the
type of the data that will be returned by the function with the return instruction.
But what if we want to return no value?

 Imagine that we want to make a function just to show a message on the screen. We do
not need it to return any value, moreover, we do not need it to receive any parameters.
For these cases, the void type was devised in the C language. Take a look at:

// void function example I'm a function!


#include <iostream.h>

void dummyfunction (void)


{
cout << "I'm a function!";
}

int main ()
{
dummyfunction ();
return 0;
}

 Although in C++ it is not necessary to specify void, its use is considered suitable to
signify that it is a function without parameters or arguments and not something else.
 What you must always be aware of is that the format for calling a function includes
specifying its name and enclosing the arguments between parenthesis. The non-
existence of arguments does not exempt us from the obligation to use parenthesis. For
that reason the call to dummyfunction is

dummyfunction ();

This clearly indicates that it is a call to a function and not the name of a variable or
anything else.

48
Arguments passed by value and by reference

 Until now, in all the functions we have seen, the parameters passed to the functions
have been passed by value. This means that when calling a function with parameters,
what we have passed to the function were values but never the specified variables
themselves. For example, suppose that we called our first function addition using the
following code :
int x=5, y=3, z;
z = addition ( x , y );
What we did in this case was to call function addition passing the values of x and y,
that means 5 and 3 respectively, not the variables themselves.

This way, when function addition is being called the value of its variables a and b
become 5 and 3 respectively, but any modification of a or b within the function addition
will not affect the values of x and y outside it, because variables x and y were not passed
themselves to the function, only their values.

 But there might be some cases where you need to manipulate from inside a function
the value of an external variable. For that purpose we have to use arguments passed
by reference, as in the function duplicate of the following example:

// passing parameters by reference x=2, y=6, z=14


#include <iostream.h>

void duplicate (int& a, int& b, int& c)


{
a*=2;
b*=2;
c*=2;
}

int main ()
{
int x=1, y=3, z=7;
duplicate (x, y, z);
cout << "x=" << x << ", y=" << y << ",
z=" << z;
return 0;
}

49
The first thing that should call your attention is that in the declaration of duplicate the type
of each argument was followed by an ampersand sign (&), that serves to specify that the
variable has to be passed by reference instead of by value, as usual.

 When passing a variable by reference we are passing the variable itself and any
modification that we do to that parameter within the function will have effect in the
passed variable outside it.

To express it another way, we have associated a, b and c with the parameters used when
calling the function (x, y and z) and any change that we do on a within the function will
affect the value of x outside. Any change that we do on b will affect y, and the same with
c and z.

That is why our program's output, that shows the values stored in x, y and z after the call
to duplicate, shows the values of the three variables of main doubled.

 If when declaring the following function:

void duplicate (int& a, int& b, int& c)

we had declared it thus:


void duplicate (int a, int b, int c)
that is, without the ampersand (&) signs, we would have not passed the variables by
reference, but their values, and therefore, the output on screen for our program would
have been the values of x, y and z without having been modified.
 Passing by reference is an effective way to allow a function to return more than one
single value. For example, here is a function that returns the previous and next
numbers of the first parameter passed.
// more than one returning value Previous=99, Next=101
#include <iostream.h>

void prevnext (int x, int& prev, int& next)


{
prev = x-1;
next = x+1;
}

int main ()
{
int x=100, y, z;
prevnext (x, y, z);

50
cout << "Previous=" << y << ", Next="
<< z;
return 0;
}

Default values in arguments

 When declaring a function we can specify a default value for each parameter. This
value will be used if that parameter is left blank when calling to the function. To do
that we simply have to assign a value to the arguments in the function declaration. If a
value for that parameter is not passed when the function is called, the default value is
used, but if a value is specified this default value is stepped on and the passed value is
used. For example:
// default values in functions 6
#include <iostream.h> 5

int divide (int a, int b=2)


{
int r;
r=a/b;
return (r);
}

int main ()
{
cout << divide (12);
cout << endl;
cout << divide (20,4);
return 0;
}

As we can see in the body of the program there are two calls to the function divide. In the
first one:

divide (12)

we have only specified one argument, but the function divide allows up to two. So the
function divide has assumed that the second parameter is 2 since that is what we have
specified to happen if this parameter is lacking (notice the function declaration, which
finishes with int b=2). Therefore the result of this function call is 6 (12/2).

In the second call:

divide (20,4)

51
there are two parameters, so the default assignation (int b=2) is stepped on by the passed
parameter, that is 4, making the result equal to 5 (20/4).

5.2 Overloaded functions

 Uses the same function name for more than one function.
 The functions must have something different about their arguments, either a different
number of arguments or arguments of different types. The compiler uses the
differences in the argument list to distinguish one function from another.
For example,

// overloaded function 2
#include <iostream.h> 2.5

int divide (int a, int b)


{
return (a/b);
}

float divide (float a, float b)


{
return (a/b);
}

int main ()
{
int x=5,y=2;
float n=5.0,m=2.0;
cout << divide (x,y);
cout << "\n";
cout << divide (n,m);
cout << "\n";
return 0;
}

In this case we have defined two functions with the same name, but one of them accepts
two arguments of type int

and the other accepts them of type float. The compiler knows which one to call in each
case by examining the types when the function is called. If it is called with two ints as
arguments it calls to the function that has two int arguments in the prototype and if it is
called with two floats it will call to the one which has two floats in its prototype.

 For simplicity I have included the same code within both functions, but this is not
compulsory. You can make two function with the same name but with completely
different behaviors.

52
5.3 Inline functions

 The inline directive can be included before a function declaration to specify that the
function must be compiled as code at the same point where it is called. This is
equivalent to declaring a macro. Its advantage is only appreciated in very short
functions, in which the resulting code from compiling the program may be faster if
the overhead of calling a function (stacking of arguments) is avoided.
 The format for its declaration is:
inline type name ( arguments ... ) { instructions ... }
and the call is just like the call to any other function. It is not necessary to include the
inline keyword before each call, only in the declaration.

5.4 Recursion

 Recursion is the property that functions have to be called by themselves. It is useful


for tasks such as some sorting methods or to calculate the factorial of a number. For
example, to obtain the factorial of a number (n) its mathematical formula is:
n! = n * (n-1) * (n-2) * (n-3) ... * 1
more concretely, 5! (factorial of 5) would be:
5! = 5 * 4 * 3 * 2 * 1 = 120
and a recursive function to do that could be this:
// factorial calculator Type a number: 9
#include <iostream.h> !9 = 362880

long factorial (long a)


{
if (a > 1)
return (a * factorial (a-1));
else
return (1);
}

int main ()
{
long l;
cout << "Type a number: ";
cin >> l;
cout << "!" << l << " = " << factorial (l);
return 0;
}

Notice how in function factorial we included a call to itself, but only if the argument is
greater than 1, since otherwise the function would perform an infinite recursive loop in
which once it arrived at 0 it would continue multiplying by all the negative numbers
(probably provoking a stack overflow error on runtime).

53
This function has a limitation because of the data type used in its design (long) for more
simplicity. In a standard system, the type long would not allow storing factorials greater
than 12!.

5.5 Prototyping functions

 Until now, we have defined the all of the functions before the first appearance of calls
to them that generally was in main leaving the function main for the end. If you try to
repeat some of the examples of functions described so far, but placing the function
main before any other function that is called from within it, you will most likely
obtain an error. The reason is that to be able to call a function it must have been
declared previously (it must be known), like we have done in all our examples.
 But there is an alternative way to avoid writing all the code of all functions before
they can be used in main or in another function. It is by prototyping functions. This
consists in making a previous shorter, but quite significant, declaration of the
complete definition so that the compiler can know the arguments and the return type
needed.

Its form is:

type name ( argument_type1, argument_type2, ...);


It is identical to the header of a function definition, except:

 It does not include a statement for the function. That means that it does not
include the body with all the instructions that are usually enclose within curly
brackets { }.
 It ends with a semicolon sign (;).
 In the argument enumeration it is enough to put the type of each argument. The
inclusion of a name for each argument as in the definition of a standard function
is optional, although recommended.

For example:
// prototyping Type a number (0 to exit): 9
#include <iostream.h> Number is odd.
Type a number (0 to exit): 6
Number is even.
void odd (int a); Type a number (0 to exit): 1030
void even (int a); Number is even.
Type a number (0 to exit): 0
int main () Number is even.
{
int i;
do {
cout << "Type a number: (0 to exit)";
cin >> i;
odd (i);
} while (i!=0);

54
return 0;
}

void odd (int a)


{
if ((a%2)!=0) cout << "Number is odd.\n";
else even (a);
}

void even (int a)


{
if ((a%2)==0) cout << "Number is
even.\n";
else odd (a);
}

This example is indeed not an example of effectiveness, I am sure that at this point you
can already make a program with the same result using only half of the code lines. But
this example illustrates how prototyping works. Moreover, in this concrete case the
prototyping of -at least- one of the two functions is necessary.

The first things that we see are the prototypes of functions odd and even:

void odd (int a);


void even (int a);
that allows these functions to be used before they are completely defined, for example, in
main, which now is located in a more logical place: the beginning of the program's code.

Nevertheless, the specific reason why this program needs at least one of the functions
prototyped is because in odd there is a call to even and in even there is a call to odd. If
none of the two functions had been previously declared, an error would have happened,
since either odd would not be visible from even (because it has not still been declared),
or even would not be visible from odd.

 Many programmers recommend that all functions be prototyped. It is also my


recommendation, mainly in case that there are many functions or in case that they are
very long. Having the prototype of all the functions in the same place can spare us
some time when determining how to call it or even ease the creation of a header file.

55

You might also like