0% found this document useful (0 votes)
0 views24 pages

Chapter 5 - Modular Programming

Chapter Five discusses modular programming, emphasizing the importance of breaking down programs into manageable functions or modules for better development and maintenance. It covers the definition, declaration, and definition of functions, along with variable scope, function arguments, and return values. The chapter also highlights the use of local and global variables, function prototypes, and the execution flow of functions.

Uploaded by

heni
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)
0 views24 pages

Chapter 5 - Modular Programming

Chapter Five discusses modular programming, emphasizing the importance of breaking down programs into manageable functions or modules for better development and maintenance. It covers the definition, declaration, and definition of functions, along with variable scope, function arguments, and return values. The chapter also highlights the use of local and global variables, function prototypes, and the execution flow of functions.

Uploaded by

heni
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/ 24

Chapter Five

Modular Programming

5.1. Definition of Functions.............................................................................................. 1

5.1.1. Declaring and Defining Functions........................................................................1

5.2. Scope of variables.....................................................................................................6

5.2.1. Local Variables................................................................................................ 6

5.2.2. Global Variables...............................................................................................7

5.3. Function Arguments................................................................................................10

5.4. Passing arguments.................................................................................................. 11

5.4.1. Pass by Value................................................................................................ 11

5.4.2. Pass by reference............................................................................................ 12

5.5. Return Values........................................................................................................ 14

5.6. Default Parameters ..................................................................................................15

5.7. Inline Functions......................................................................................................17

5.8. Recursive Functions................................................................................................ 19


Modular programming and Modules
Modular programming is breaking down the design of a program into individual
components (modules) that can be programmed and tested independently. It is a
requirement for effective development and maintenance of large programs and projects .
With modular programming, procedures of a common functionality are grouped together
into separate modules. A program therefore no longer consists of only one single part. It is
now divided into several smaller parts which interact and which form the whole program.

5.5. Definition of Functions

Modules in C++ are called functions. A function is a subprogram that can act on data and
return a value. Every C++ program has at least one function, m a i n ( ) . When your program
starts, m a i n ( ) is called automatically. m a i n ( ) might call other functions, some of which
might call still others. Each function has its own name, and when that name is encountered,
the execution of the program branches to the body of that function. When the function
returns, execution resumes on the next line of the calling function. When a program calls a
function, execution switches to the function and then resumes at the line after the function
call. Well-designed functions perform a specific and easily understood task. Complicated
tasks should be broken down into multiple functions, and then each can be called in turn.
Functions come in two varieties: user-defined and built-in. Built-in functions are part of
your compiler package--they are supplied by the manufacturer for your use. In this chapter
we will discuss about user-defined functions.

5.5.5. Declaring and Defining Functions

Using functions in your program requires that you first declare the function and that you
then define the function. The declaration tells the compiler the name, return type, and
parameters of the function. The definition tells the compiler how the function works. No
function can be called from any other function that hasn't first been declared. The
declaration of a function is called its prototype.

5.5.5.5. Declaring the Function

There are three ways to declare a function:

· Write your prototype into a file, and then use the # i n c l u d e directive to include it in
your program.
· Write the prototype into the file in which your function is used.
· Define the function before it is called by any other function. When you do this, the
definition acts as its own declaration.

Although you can define the function before using it, and thus avoid the necessity of
creating a function prototype, this is not good programming practice for three reasons. First,
it is a bad idea to require that functions appear in a file in a particular order. Doing so
makes it hard to maintain the program as requirements change. Second, it is possible that
function A ( ) needs to be able to call function B ( ) , but function B ( ) also needs to be able to

-2-
call function A ( ) under some circumstances. It is not possible to define function A ( ) before
you define function B ( ) and also to define function B ( ) before you define function A ( ) , so
at least one of them must be declared in any case. Third, function prototypes are a good and
powerful debugging technique. If your prototype declares that your function takes a
particular set of parameters, or that it returns a particular type of value, and then your
function does not match the prototype, the compiler can flag your error instead of waiting
for it to show itself when you run the program.

Function Prototypes

Many of the built-in functions you use have their function prototypes already written in the
files you include in your program by using # i n c l u d e . For functions you write yourself, you
must include the prototype. The function prototype is a statement, which means it ends with
a semicolon. It consists of the function's return type, name, and parameter list. The
parameter list is a list of all the parameters and their types, separated by commas. Function
Prototype Syntax:

return_type function_name ( [type [parameterName1] type [parameterName2]]...);

The function prototype and the function definition must agree exactly about the return type,
the name, and the parameter list. If they do not agree, you will get a compile-time error.
Note, however, that the function prototype does not need to contain the names of the
parameters, just their types. A prototype that looks like this is perfectly legal:

long Area(int, int);

This prototype declares a function named A r e a ( ) that returns a l o n g and that has two
parameters, both integers. Although this is legal, it is not a good idea. Adding parameter
names makes your prototype clearer. The same function with named parameters might be

long Area(int length, int width);

It is now obvious what this function does and what the parameters are. Note that all
functions have a return type. If none is explicitly stated, the return type defaults to i n t .
Your programs will be easier to understand, however, if you explicitly declare the return
type of every function, including m a i n ( ) .

Function Prototype Examples


long FindArea(long length, long width); // returns long, has two parameters
void PrintMessage(int messageNumber); // returns void, has one parameter
int GetChoice(); // returns int, has no parameters
BadFunction(); // returns int, has no parameters

Listing 5.1 demonstrates a program that includes a function prototype for the A r e a ( )
function.

-3-
Listing 5.1. A function declaration and the definition and use of that function.

1: // Listing 5.1 - demonstrates the use of function prototypes


2:
3: typedef unsigned short USHORT;
4: #include <iostream.h>
5: USHORT FindArea(USHORT length, USHORT width); //function prototype
6:
7: int main()
8: {
9: USHORT lengthOfY ard;
10: USHORT widthOfY ard;
11: USHORT areaOfY ard;
12:
13: cout << "\nHow wide is your yard? ";
14: cin >> widthOfY ard;
15: cout << "\nHow long is your yard? ";
16: cin >> lengthOfY ard;
17:
18: areaOfY ard= FindArea(lengthOfY ard,widthOfY ard);
19:
20: cout << "\nY our yard is ";
21: cout << areaOfY ard;
22: cout << " square feet\n\n";
23: return 0;
24: }
25:
26: USHORT FindArea(USHORT l, USHORT w)
27: {
28: return l * w;
29: }
Output: How wide is your yard? 100

How long is your yard? 200

Your yard is 20000 square feet

Analysis: The prototype for the F i n d A r e a ( ) function is on line 5. Compare the prototype
with the definition of the function on line 26. Note that the name, the return type, and the
parameter types are the same. If they were different, a compiler error would have been
generated. In fact, the only required difference is that the function prototype ends with a
semicolon and has no body. Also note that the parameter names in the prototype are
l e n g t h and w i d t h , but the parameter names in the definition are l and w . The names in the
prototype are not used; they are there as information to the programmer. When they are
included, they should match the implementation when possible. This is a matter of good
programming style and reduces confusion, but it is not required, as you see here.

-4-
The arguments are passed in to the function in the order in which they are declared and
defined, but there is no matching of the names. Had you passed in w i d t h O f Y a r d , followed
by l e n g t h O f Y a r d , the F i n d A r e a ( ) function would have used the value in w i d t h O f Y a r d
for l e n g t h and l e n g t h O f Y a r d for w i d t h . The body of the function is always enclosed in
braces, even when it consists of only one statement, as in this case.

5.5.5.5. Defining the Function

The definition of a function consists of the function header and its body. The header is
exactly like the function prototype, except that the parameters must be named, and there is
no terminating semicolon. The body of the function is a set of statements enclosed in braces.
Function Definition Syntax

return_type function_name ( [type parameterName1], [type parameterName2]...)


{
statements;
}

A function prototype tells the compiler the return type, name, and parameter list. Func-tions
are not required to have parameters, and if they do, the prototype is not required to list their
names, only their types. A prototype always ends with a semicolon (;). A function
definition must agree in return type and parameter list with its prototype. It must provide
names for all the parameters, and the body of the function definition must be surrounded by
braces. All statements within the body of the function must be terminated with semicolons,
but the function itself is not ended with a semicolon; it ends with a closing brace. If the
function returns a value, it should end with a r e t u r n statement, although r e t u r n
statements can legally appear anywhere in the body of the function. Every function has a
return type. If one is not explicitly designated, the return type will be i n t . Be sure to give
every function an explicit return type. If a function does not return a value, its return type
will be v o i d .

Function Definition Examples


l o n g A r e a ( l o n g l , l o n g w )
{
r e t u r n l * w ;
}

v o i d P r i n t M e s s a g e ( i n t w h i c h M s g )
{
i f ( w h i c h M s g = = 0 )
c o u t < < " H e l l o . \ n " ;
i f ( w h i c h M s g = = 1 )
c o u t < < " G o o d b y e . \ n " ;
i f ( w h i c h M s g > 1 )
c o u t < < " I ' m c o n f u s e d . \ n " ;
}
Function Statements

-5-
There is virtually no limit to the number or types of statements that can be in a function
body. Although you can't define another function from within a function, you can call a
function, and of course m a i n ( ) does just that in nearly every C++ program. Functions can
even call themselves, which is discussed soon, in the section on recursion. Although there
is no limit to the size of a function in C++, well-designed functions tend to be small. Many
programmers advise keeping your functions short enough to fit on a single screen so that
you can see the entire function at one time. This is a rule of thumb, often broken by very
good programmers, but a smaller function is easier to understand and maintain. Each
function should carry out a single, easily understood task. If your functions start getting
large, look for places where you can divide them into component tasks.

Execution of Functions

When you call a function, execution begins with the first statement after the opening brace
({ ). Branching can be accomplished by using the i f statement. Functions can also call
other functions and can even call themselves (see the section "Recursion," later in this
chapter). Each function has its own name, and when that name is encountered, the
execution of the program branches to the body of that function. When the function returns,
execution resumes on the next line of the calling function. This flow is illustrated in the
following figure.

5.5. Scope of variables


A variable has scope, which determines how long it is available to your program and where
it can be accessed. There are two scopes Local and Global.

5.5.5. Local Variables

Not only can you pass in variables to the function, but you also can declare variables within
the body of the function. This is done using local variables, so named because they exist

-6-
only locally within the function itself. When the function returns, the local variables are no
longer available. Local variables are defined like any other variables. The parameters
passed in to the function are also considered local variables and can be used exactly as if
they had been defined within the body of the function. Variables declared within the
function are said to have "local scope." That means that they are visible and usable only
within the function in which they are defined. In fact, in C++ you can define variables
anywhere within the function, not just at its top. The scope of the variable is the block in
which it is defined. Thus, if you define a variable inside a set of braces within the function,
that variable is available only within that block. Listing 5.2 is an example of using
parameters and locally defined variables within a function.

Listing 5.2. The use of local variables and parameters.

1 : # i n c l u d e < i o s t r e a m . h >
2 :
3 : f l o a t C o n v e r t ( f l o a t ) ;
4 : i n t m a i n ( )
5 : {
6 : f l o a t T e m p F e r ;
7 : f l o a t T e m p C e l ;
8 :
9 : c o u t < < " P l e a s e e n t e r t h e t e m p e r a t u r e i n F a h r e n h e i t : " ;
1 0 : c i n > > T e m p F e r ;
1 1 : T e m p C e l = C o n v e r t ( T e m p F e r ) ;
1 2 : c o u t < < " \ n H e r e ' s t h e t e m p e r a t u r e i n C e l s i u s : " ;
1 3 : c o u t < < T e m p C e l < < e n d l ;
1 4 : r e t u r n 0 ;
1 5 : }
1 6 :
1 7 : f l o a t C o n v e r t ( f l o a t T F e r )
1 8 : {
1 9 : f l o a t T C e l ;
2 0 : T C e l = ( ( T F e r - 3 2 ) * 5 ) / 9 ;
2 1 : r e t u r n T C e l ;
2 2 : }

O u t p u t : P l e a s e e n t e r t h e t e m p e r a t u r e i n F a h r e n h e i t : 2 1 2

H e r e ' s t h e t e m p e r a t u r e i n C e l s i u s : 1 0 0

P l e a s e e n t e r t h e t e m p e r a t u r e i n F a h r e n h e i t : 3 2

H e r e ' s t h e t e m p e r a t u r e i n C e l s i u s : 0

P l e a s e e n t e r t h e t e m p e r a t u r e i n F a h r e n h e i t : 8 5

H e r e ' s t h e t e m p e r a t u r e i n C e l s i u s : 2 9 . 4 4 4 4

Analysis: On lines 6 and 7, two f l o a t variables are declared, one to hold the temperature
in Fahrenheit and one to hold the temperature in degrees Celsius. The user is prompted to
enter a Fahrenheit temperature on line 9, and that value is passed to the function C o n v e r t ( ) .
Execution jumps to the first line of the function C o n v e r t ( ) on line 19, where a local

-7-
variable, named T C e l , is declared. Note that this is local variable that exists only within the
function C o n v e r t ( ) . The value passed as a parameter, T F e r , is also just a local copy of the
variable passed in by m a i n ( ) .The local function variable T C e l is assigned the value that
results from subtracting 32 from the parameter T F e r , multiplying by 5, and then dividing
by 9. This value is then returned as the return value of the function, and on line 11 it is
assigned to the variable T e m p C e l in the m a i n ( ) function. The value is printed on line 13.
The program is run three times. The first time, the value 2 1 2 is passed in to ensure that the
boiling point of water in degrees Fahrenheit (212) generates the correct answer in degrees
Celsius (100). The second test is the freezing point of water. The third test is a random
number chosen to generate a fractional result.

Variables declared within a block are scoped to that block; they can be accessed only
within that block and "go out of existence" when that block ends. Global variables have
global scope and are available anywhere within your program. Normally scope is obvious,
but there are some tricky exceptions. Currently, variables declared within the header of a
f o r loop ( f o r i n t i = 0 ; i < S o m e V a l u e ; i + + ) are scoped to the block in which the f o r
loop is created.

5.5.5. Global Variables

Variables defined outside of any function have global scope and thus are available from
any function in the program, including m a i n ( ) . Local variables with the same name as
global variables do not change the global variables. A local variable with the same name as
a global variable hides the global variable, however. If a function has a variable with the
same name as a global variable, the name refers to the local variable--not the global--when
used within the function. Listing 5.3 illustrates these points.

Listing 5.3. Demonstrating global and local variables.


1 : # i n c l u d e < i o s t r e a m . h >
2 : v o i d m y F u n c t i o n ( ) ; / / p r o t o t y p e
3 :
4 : i n t x = 5 , y = 7 ; / / g l o b a l v a r i a b l e s
5 : i n t m a i n ( )
6 : {
7 :
8 : c o u t < < " x
f r o m m a i n : " < < x < < " \ n " ;
9 : c o u t < < " y f r o m m a i n : " < < y < < " \ n \ n " ;
1 0 : m y F u n c t i o n ( ) ;
1 1 : c o u t < < " B a c k f r o m m y F u n c t i o n ! \ n \ n " ;
1 2 : c o u t < < " x f r o m m a i n : " < < x < < " \ n " ;
1 3 : c o u t < < " y f r o m m a i n : " < < y < < " \ n " ;
1 4 : r e t u r n 0 ;
1 5 : }
1 6 :
1 7 : v o i d m y F u n c t i o n ( )
1 8 : {
1 9 : i n t y = 1 0 ;
2 0 :
2 1 : c o u t < < " x f r o m m y F u n c t i o n : " < < x < < " \ n " ;

-8-
2 2 : c o u t < < " y f r o m m y F u n c t i o n : " < < y < < " \ n \ n " ;
2 3 : }

O u t p u t : x f r o m m a i n : 5
y f r o m m a i n : 7

x f r o m m y F u n c t i o n : 5
y f r o m m y F u n c t i o n : 1 0

B a c k f r o m m y F u n c t i o n !

x f r o m m a i n : 5
y f r o m m a i n : 7

Analysis: This simple program illustrates a few key, and potentially confusing, points
about local and global variables. On line 1, two global variables, x and y , are declared. The
global variable x is initialized with the value 5 , and the global variable y is initialized with
the value 7 . On lines 8 and 9 in the function m a i n ( ) , these values are printed to the screen.
Note that the function m a i n ( ) defines neither variable; because they are global, they are
already available to m a i n ( ) .

When m y F u n c t i o n ( ) is called on line 10, program execution passes to line 18, and a local
variable, y , is defined and initialized with the value 1 0 . On line 21, m y F u n c t i o n ( ) prints
the value of the variable x , and the global variable x is used, just as it was in m a i n ( ) . On
line 22, however, when the variable name y is used, the local variable y is used, hiding the
global variable with the same name.The function call ends, and control returns to m a i n ( ) ,
which again prints the values in the global variables. Note that the global variable y was
totally unaffected by the value assigned to m y F u n c t i o n ( ) 's local y variable.

Listing 5.4. Variables scoped within a block.


1 : / / L i s t i n g 5 . 4 - d e m o n s t r a t e s v a r i a b l e s
2 : / / s c o p e d w i t h i n a b l o c k
3 :
4 : # i n c l u d e < i o s t r e a m . h >
5 :
6 : v o i d m y F u n c ( ) ;
7 :
8 : i n t m a i n ( )
9 : {
1 0 : i n t x = 5 ;
1 1 : c o u t < < " \ n I n m a i n x i s : " < < x ;
1 2 :
1 3 : m y F u n c ( ) ;
1 4 :
1 5 : c o u t < < " \ n B a c k i n m a i n , x i s : " < < x ;
1 6 : r e t u r n 0 ;
1 7 : }
1 8 :
1 9 : v o i d m y F u n c ( )
2 0 : {
2 1 :

-9-
2 2 : i n t x = 8 ;
2 3 : c o u t < < " \ n I n m y F u n c , l o c a l x : " < < x < < e n d l ;
2 4 :
2 5 : {
2 6 : c o u t < < " \ n I n b l o c k i n m y F u n c , x i s : " < < x ;
2 7 :
2 8 : i n t x = 9 ;
2 9 :
3 0 : c o u t < < " \ n V e r y l o c a l x : " < < x ;
3 1 : }
3 2 :
3 3 : c o u t < < " \ n O u t o f b l o c k , i n m y F u n c , x : " < < x < < e n d l ;
3 4 : }

O u t p u t : I n m a i n x i s : 5
I n m y F u n c , l o c a l x : 8

I n b l o c k i n m y F u n c , x i s : 8
V e r y l o c a l x : 9
O u t o f b l o c k , i n m y F u n c , x : 8

B a c k i n m a i n , x i s : 5

Analysis: This program begins with the initialization of a local variable, x , on line 10, in
m a i n ( ) . The printout on line 11 verifies that x was initialized with the value 5 . M y F u n c ( ) is
called, and a local variable, also named x , is initialized with the value 8 on line 22. Its value
is printed on line 23. A block is started on line 25, and the variable x from the function is
printed again on line 26. A new variable also named x , but local to the block, is created on
line 28 and initialized with the value 9 . The value of the newest variable x is printed on line
30. The local block ends on line 31, and the variable created on line 28 goes "out of scope"
and is no longer visible.

When x is printed on line 33, it is the x that was declared on line 22. This x was unaffected
by the x that was defined on line 28; its value is still 8 . On line 34, M y F u n c ( ) goes out of
scope, and its local variable x becomes unavailable. Execution returns to line 15, and the
value of the local variable x , which was created on line 10, is printed. It was unaffected by
either of the variables defined in M y F u n c ( ) . Needless to say, this program would be far less
confusing if these three variables were given unique names!

Global Variables: A Word of Caution

In C++, global variables are legal, but they are almost never used. Globals are dangerous
because they are shared data, and one function can change a global variable in a way that is
invisible to another function. This can and does create bugs that are very difficult to find.

Scope resolution operator

When a local variable has the same name as a global variable, all references to the variable
name made with in the scope of the local variable. This situation is illustrated in the
following program.

- 10-
# i n c l u d e < i o s t r e a m . h >
f l o a t n u m = 4 2 . 8 ; / / g l o b a l v a r i a b l e
i n t m a i n ( )
{
f l o a t n u m = 2 6 . 4 ; / / l o c a l v a r i a b l e
c o u t < < " t h e v a l u e o f n u m i s : " < < n u m < < e n d l ;
r e t u r n 0 ;
}
The output of the above program is:
t h e v a l u e o f n u m i s : 2 6 . 4

As shown by the above output, the local variable name takes precedence ovger the global
variable. In such cases, we can still access the global variable by using C++'s scope
resolution operator (::). This operator must be placed immediately before the variable name,
as in ::num. When used in this manner, the :: tells the compiler to use global variable.E.g

f l o a t n u m = 4 2 . 8 ; / / g l o b a l v a r i a b l e
i n t m a i n ( )
{
f l o a t n u m = 2 6 . 4 ; / / l o c a l v a r i a b l e
c o u t < < " t h e v a l u e o f n u m i s : " < < : : n u m < < e n d l ;
r e t u r n 0 ;
}
The out is:
t h e v a l u e o f t h e n u m b e r i s 4 2 . 8

As indicated the above output, the scope resolution operator causes the global, rather the
local variable to be accessed.

5.5. Function Arguments

Function arguments do not have to all be of the same type. It is perfectly reasonable to
write a function that takes an integer, two l o n g s, and a character as its arguments. Any
valid C++ expression can be a function argument, including constants, mathematical and
logical expressions, and other functions that return a value.

Using Functions as Parameters to Functions

Although it is legal for one function to take as a parameter a second function that returns a
value, it can make for code that is hard to read and hard to debug. As an example, say you
have the functions d o u b l e ( ) , t r i p l e ( ) , s q u a r e ( ) , and c u b e ( ) , each of which returns a
value. You could write

A n s w e r = ( d o u b l e ( t r i p l e ( s q u a r e ( c u b e ( m y V a l u e ) ) ) ) ) ;

This statement takes a variable, m y V a l u e , and passes it as an argument to the function


c u b e ( ) , whose return value is passed as an argument to the function s q u a r e ( ) , whose
return value is in turn passed to t r i p l e ( ) , and that return value is passed to d o u b l e ( ) . The
return value of this doubled, tripled, squared, and cubed number is now passed to A n s w e r .

- 11-
It is difficult to be certain what this code does (was the value tripled before or after it was
squared?), and if the answer is wrong it will be hard to figure out which function failed. An
alternative is to assign each step to its own intermediate variable:

u n s i g n e d l o n g m y V a l u e = 2 ;
u n s i g n e d l o n g c u b e d = c u b e ( m y V a l u e ) ; / / c u b e d = 8
u n s i g n e d l o n g s q u a r e d = s q u a r e ( c u b e d ) ; / / s q u a r e d = 6 4
u n s i g n e d l o n g t r i p l e d = t r i p l e ( s q u a r e d ) ; / / t r i p l e d = 1 9 6
u n s i g n e d l o n g A n s w e r = d o u b l e ( t r i p l e d ) ; / / A n s w e r = 3 9 2

Now each intermediate result can be examined, and the order of execution is explicit.

5.5. Passing arguments


5.5.5. Pass by Value

The arguments passed in to the function are local to the function. Changes made to the
arguments do not affect the values in the calling function. This is known as passing by
value, which means a local copy of each argument is made in the function. These local
copies are treated just like any other local variables. Listing 5.5 illustrates this point.

Listing 5.5. A demonstration of passing by value.


1 : / / L i s t i n g 5 . 5 - d e m o n s t r a t e s p a s s i n g b y v a l u e
2 :
3 : # i n c l u d e < i o s t r e a m . h >
4 :
5 : v o i d s w a p ( i n t x , i n t y ) ;
6 :
7 : i n t m a i n ( )
8 : {
9 : i n t x = 5 , y = 1 0 ;
1 0 :
1 1 : c o u t < <
" M a i n . B e f o r e s w a p , x : " < < x < < " y : " < < y < < " \ n " ;
1 2 : s w a p ( x , y ) ;
1 3 : c o u t < < " M a i n . A f t e r s w a p , x : " < < x < < " y : " < < y < < " \ n " ;
1 4 : r e t u r n 0 ;
1 5 : }
1 6 :
1 7 : v o i d s w a p ( i n t x , i n t y )
1 8 : {
1 9 : i n t t e m p ;
2 0 :
2 1 : c o u t < < " S w a p . B e f o r e s w a p , x : " < < x < < " y : " < < y < < " \ n " ;
2 2 :
2 3 : t e m p = x ;
2 4 : x = y ;
2 5 : y = t e m p ;
2 6 :
2 7 : c o u t < < " S w a p . A f t e r s w a p , x : " < < x < < " y : " < < y < < " \ n " ;
2 8 :
2 9 : }

- 12-
O u t p u t : M a i n . B e f o r e s w a p , x : 5 y : 1 0
S w a p . B e f o r e s w a p , x : 5 y : 1 0
S w a p . A f t e r s w a p , x : 1 0 y : 5
M a i n . A f t e r s w a p , x : 5 y : 1 0

Analysis: This program initializes two variables in m a i n ( ) and then passes them to the
s w a p ( ) function, which appears to swap them. When they are examined again in m a i n ( ) ,
however, they are unchanged! The variables are initialized on line 9, and their values are
displayed on line 11. s w a p ( ) is called, and the variables are passed in. Execution of the
program switches to the s w a p ( ) function, where on line 21 the values are printed again.
They are in the same order as they were in m a i n ( ) , as expected. On lines 23 to 25 the
values are swapped, and this action is confirmed by the printout on line 27. Indeed, while in
the s w a p ( ) function, the values are swapped. Execution then returns to line 13, back in
m a i n ( ) , where the values are no longer swapped.

As you've figured out, the values passed in to the s w a p ( ) function are passed by value,
meaning that copies of the values are made that are local to s w a p ( ) . These local variables
are swapped in lines 23 to 25, but the variables back in m a i n ( ) are unaffected.

5.5.5. Pass by reference

In C++, passing by reference is accomplished in two ways: using pointers and using
references. The syntax is different, but the net effect is the same. Rather than a copy being
created within the scope of the function, the actual original object is passed into the
function. Passing an object by reference allows the function to change the object being
referred to. In previous section showed that a call to the s w a p ( ) function did not affect the
values in the calling function.

Listing 9.7. swap() rewritten with references.


1 : / / L i s t i n g 9 . 7 D e m o n s t r a t e s p a s s i n g b y r e f e r e n c e
2 : / / u s i n g r e f e r e n c e s !
3 :
4 : # i n c l u d e < i o s t r e a m . h >
5 :
6 : v o i d s w a p ( i n t & x , i n t & y ) ;
7 :
8 : i n t m a i n ( )
9 : {
1 0 : i n t x = 5 , y = 1 0 ;
1 1 :
1 2 : c o u t < < " M a i n . B e f o r e s w a p , x : " < < x < < " y : " < < y < < " \ n " ;
1 3 : s w a p ( x , y ) ;
1 4 : c o u t < < " M a i n . A f t e r s w a p , x : " < < x < < " y : " < < y < < " \ n " ;
1 5 : r e t u r n 0 ;
1 6 : }
1 7 :
1 8 : v o i d s w a p ( i n t & r x , i n t & r y )
1 9 : {

- 13-
2 0 : i n t t e m p ;
2 1 :
2 2 : c o u t < < " S w a p . B e f o r e s w a p , r x : " < < r x < < " r y : " < < r y < < " \ n " ;
2 3 :
2 4 : t e m p = r x ;
2 5 : r x = r y ;
2 6 : r y = t e m p ;
2 7 :
2 8 : c o u t < < " S w a p . A f t e r s w a p , r x : " < < r x < < " r y : " < < r y < < " \ n " ;
2 9 :
3 0 : }
O u t p u t : M a i n . B e f o r e s w a p , x : 5 y : 1 0
S w a p . B e f o r e s w a p , r x : 5 r y : 1 0
S w a p . A f t e r s w a p , r x : 1 0 r y : 5
M a i n . A f t e r s w a p , x : 1 0 , y : 5

A n a y l s i s : wo variables are declared on line 10 and their values are printed on line 12.
T
On line 13, the function s w a p ( ) is called, but note that x and y , not their addresses, are
passed. The calling function simply passes the variables.
When s w a p ( ) is called, program execution jumps to line 18, where the variables are
identified as references. Their values are printed on line 22, but note that no special
operators are required. These are aliases for the original values, and can be used as such.
On lines 24-26, the values are swapped, and then they're printed on line 28. Program
execution jumps back to the calling function, and on line 14, the values are printed in
m a i n ( ) . Because the parameters to s w a p ( ) are declared to be references, the values from
m a i n ( ) are passed by reference, and thus are changed in m a i n ( ) as well. References
provide the convenience and ease of use of normal variables.

5.5. Return Values

Functions return a value or return v o i d . V o i d is a signal to the compiler that no value will
be returned. To return a value from a function, write the keyword r e t u r n followed by the
value you want to return. The value might itself be an expression that returns a value. For
example:

r e t u r n 5 ;
r e t u r n ( x > 5 ) ;
r e t u r n ( M y F u n c t i o n ( ) ) ;

These are all legal r e t u r n statements, assuming that the function M y F u n c t i o n ( ) itself
returns a value. The value in the second statement, r e t u r n ( x > 5 ) , will be zero if x is not
greater than 5, or it will be 1 . What is returned is the value of the expression, 0 (f a l s e ) or 1
(t r u e ), not the value of x .

When the r e t u r n keyword is encountered, the expression following r e t u r n is returned as


the value of the function. Program execution returns immediately to the calling function,
and any statements following the return are not executed. It is legal to have more than one
r e t u r n statement in a single function. Listing 5.6 illustrates this idea.

- 14-
Listing 5.6. A demonstration of multiple return statements.
1 : / / L i s t i n g 5 . 6 - d e m o n s t r a t e s m u l t i p l e r e t u r n
2 : / / s t a t e m e n t s
3 :
4 : # i n c l u d e < i o s t r e a m . h >
5 :
6 : i n t D o u b l e r ( i n t A m o u n t T o D o u b l e ) ;
7 :
8 : i n t m a i n ( )
9 : {
1 0 :
1 1 : i n t r e s u l t = 0 ;
1 2 : i n t i n p u t ;
1 3 :
1 4 : c o u t < < " E n t e r a n u m b e r b e t w e e n 0 a n d 1 0 , 0 0 0 t o d o u b l e : " ;
1 5 : c i n > > i n p u t ;
1 6 :
1 7 : c o u t < < " \ n B e f o r e d o u b l e r i s c a l l e d . . . " ;
1 8 : c o u t < < " \ n i n p u t : " < < i n p u t < < " d o u b l e d : " < < r e s u l t < < " \ n " ;
1 9 :
2 0 : r e s u l t = D o u b l e r ( i n p u t ) ;
2 1 :
2 2 : c o u t < < " \ n B a c k f r o m D o u b l e r . . . \ n " ;
2 3 : c o u t < < " \ n i n p u t : " < < i n p u t < < " d o u b l e d : " < < r e s u l t < < " \ n " ;
2 4 :
2 5 :
2 6 : r e t u r n 0 ;
2 7 : }
2 8 :
2 9 : i n t D o u b l e r ( i n t o r i g i n a l )
3 0 : {
3 1 : i f ( o r i g i n a l < = 1 0 0 0 0 )
3 2 : r e t u r n o r i g i n a l * 2 ;
3 3 : e l s e
3 4 : r e t u r n - 1 ;
3 5 : c o u t < < " Y o u c a n ' t g e t h e r e ! \ n " ;
3 6 : }
O u t p u t : E n t e r a n u m b e r b e t w e e n 0 a n d 1 0 , 0 0 0 t o d o u b l e : 9 0 0 0

B e f o r e d o u b l e r i s c a l l e d . . .
i n p u t : 9 0 0 0 d o u b l e d : 0

B a c k f r o m d o u b l e r . . .

i n p u t : 9 0 0 0 d o u b l e d : 1 8 0 0 0

E n t e r a n u m b e r b e t w e e n 0 a n d 1 0 , 0 0 0 t o d o u b l e : 1 1 0 0 0

B e f o r e d o u b l e r i s c a l l e d . . .
i n p u t : 1 1 0 0 0 d o u b l e d : 0

B a c k f r o m d o u b l e r . . .
i n p u t : 1 1 0 0 0 d o u b l e d : - 1

- 15-
Analysis: A number is requested on lines 14 and 15, and printed on line 18, along with the
local variable result. The function D o u b l e r ( ) is called on line 20, and the input value is
passed as a parameter. The result will be assigned to the local variable r e s u l t , and the
values will be reprinted on lines 22 and 23. On line 31, in the function D o u b l e r ( ) , the
parameter is tested to see whether it is greater than 10,000. If it is not, the function returns
twice the original number. If it is greater than 10,000, the function returns - 1 as an error
value. The statement on line 35 is never reached, because whether or not the value is
greater than 10,000, the function returns before it gets to line 35, on either line 32 or line 34.
A good compiler will warn that this statement cannot be executed, and a good programmer
will take it out!

5.5. Default Parameters

For every parameter you declare in a function prototype and definition, the calling function
must pass in a value. The value passed in must be of the declared type. Thus, if you have a
function declared as

l o n g m y F u n c t i o n ( i n t ) ;

the function must in fact take an integer variable. If the function definition differs, or if you
fail to pass in an integer, you will get a compiler error. The one exception to this rule is if
the function prototype declares a default value for the parameter. A default value is a value
to use if none is supplied. The preceding declaration could be rewritten as

l o n g m y F u n c t i o n ( i n t x = 5 0 ) ;

This prototype says, "m y F u n c t i o n ( ) returns a l o n g and takes an integer parameter. If an


argument is not supplied, use the default value of 5 0 ." Because parameter names are not
required in function prototypes, this declaration could have been written as

l o n g m y F u n c t i o n ( i n t = 5 0 ) ;

The function definition is not changed by declaring a default parameter. The function
definition header for this function would be

l o n g m y F u n c t i o n ( i n t x )

If the calling function did not include a parameter, the compiler would fill x with the
default value of 5 0 . The name of the default parameter in the prototype need not be the
same as the name in the function header; the default value is assigned by position, not name.
Any or all of the function's parameters can be assigned default values. The one restriction is
this: If any of the parameters does not have a default value, no previous parameter may
have a default value.

If the function prototype looks like

l o n g m y F u n c t i o n ( i n t P a r a m 1 , i n t P a r a m 2 , i n t P a r a m 3 ) ;

- 16-
you can assign a default value to P a r a m 2 only if you have assigned a default value to
P a r a m 3 . You can assign a default value to P a r a m 1 only if you've assigned default values to
both P a r a m 2 and P a r a m 3 . Listing 5.7 demonstrates the use of default values.

Listing 5.7. A demonstration of default parameter values.


1 : / / L i s t i n g 5 . 7 - d e m o n s t r a t e s u s e
2 : / / o f d e f a u l t p a r a m e t e r v a l u e s
3 :
4 : # i n c l u d e < i o s t r e a m . h >
5 :
6 : i n t A r e a C u b e ( i n t l e n g t h , i n t w i d t h = 2 5 , i n t h e i g h t = 1 ) ;
7 :
8 : i n t m a i n ( )
9 : {
1 0 : i n t l e n g t h = 1 0 0 ;
1 1 : i n t w i d t h = 5 0 ;
1 2 : i n t h e i g h t = 2 ;
1 3 : i n t a r e a ;
1 4 :
1 5 : a r e a = A r e a C u b e ( l e n g t h , w i d t h , h e i g h t ) ;
1 6 : c o u t < < " F i r s t a r e a e q u a l s : " < < a r e a < < " \ n " ;
1 7 :
1 8 : a r e a = A r e a C u b e ( l e n g t h , w i d t h ) ;
1 9 : c o u t < < " S e c o n d t i m e a r e a e q u a l s : " < < a r e a < < " \ n " ;
2 0 :
2 1 : a r e a = A r e a C u b e ( l e n g t h ) ;
2 2 : c o u t < < " T h i r d t i m e a r e a e q u a l s : " < < a r e a < < " \ n " ;
2 3 : r e t u r n 0 ;
2 4 : }
2 5 :
2 6 : A r e a C u b e ( i n t l e n g t h , i n t w i d t h , i n t h e i g h t )
2 7 : {
2 8 :
2 9 : r e t u r n ( l e n g t h * w i d t h * h e i g h t ) ;
3 0 : }

O u t p u t : F i r s t a r e a e q u a l s : 1 0 0 0 0
S e c o n d t i m e a r e a e q u a l s : 5 0 0 0
T h i r d t i m e a r e a e q u a l s : 2 5 0 0

Analysis: On line 6, the A r e a C u b e ( ) prototype specifies that the A r e a C u b e ( ) function


takes three integer parameters. The last two have default values. This function computes the
area of the cube whose dimensions are passed in. If no w i d t h is passed in, a w i d t h of 25 is
used and a h e i g h t of 1 is used. If the w i d t h but not the h e i g h t is passed in, a h e i g h t of 1
is used. It is not possible to pass in the h e i g h t without passing in a w i d t h . On lines 10-12,
the dimensions l e n g t h , h e i g h t , and w i d t h are initialized, and they are passed to the
A r e a C u b e ( ) function on line 15. The values are computed, and the result is printed on line
16. Execution returns to line 18, where A r e a C u b e ( ) is called again, but with no value for
h e i g h t . The default value is used, and again the dimensions are computed and printed.
Execution returns to line 21, and this time neither the w i d t h nor the h e i g h t is passed in.

- 17-
Execution branches for a third time to line 27. The default values are used. The area is
computed and then printed.

DO remember that function parameters act as local variables within the function. DON'T
try to create a default value for a first parameter if there is no default value for the second.
DON'T forget that arguments passed by value can not affect the variables in the calling
function. DON'T forget that changes to a global variable in one function change that
variable for all functions.

5.5. Inline Functions

When you define a function, normally the compiler creates just one set of instructions in
memory. When you call the function, execution of the program jumps to those instructions,
and when the function returns, execution jumps back to the next line in the calling function.
If you call the function 10 times, your program jumps to the same set of instructions each
time. This means there is only one copy of the function, not 10.

There is some performance overhead in jumping in and out of functions. It turns out that
some functions are very small, just a line or two of code, and some efficiency can be gained
if the program can avoid making these jumps just to execute one or two instructions. When
programmers speak of efficiency, they usually mean speed: the program runs faster if the
function call can be avoided.

If a function is declared with the keyword i n l i n e , the compiler does not create a real
function: it copies the code from the inline function directly into the calling function. No
jump is made; it is just as if you had written the statements of the function right into the
calling function.

Syntax

inline return_type function_name ( [type parameterName1], [type


parameterName2]...)
{
statements;
}

Note that inline functions can bring a heavy cost. If the function is called 10 times, the
inline code is copied into the calling functions each of those 10 times. The tiny
improvement in speed you might achieve is more than swamped by the increase in size of
the executable program. What's the rule of thumb? If you have a small function, one or two
statements, it is a candidate for i n l i n e . When in doubt, though, leave it out. Listing 5.9
demonstrates an i n l i n e function.

Listing 5.9. Demonstrates an inline function.


1 : / / L i s t i n g 5 . 9 - d e m o n s t r a t e s i n l i n e f u n c t i o n s
2 :

- 18-
3 : # i n c l u d e < i o s t r e a m . h >
4 :
5 : i n l i n e i n t D o u b l e ( i n t ) ;
6 :
7 : i n t m a i n ( )
8 : {
9 : i n t t a r g e t ;
1 0 :
1 1 : c o u t < <
" E n t e r a n u m b e r t o w o r k w i t h : " ;
1 2 : c i n > > t a r g e t ;
1 3 : c o u t < < " \ n " ;
1 4 :
1 5 : t a r g e t = D o u b l e ( t a r g e t ) ;
1 6 : c o u t < < " T a r g e t : " < < t a r g e t < < e n d l ;
1 7 :
1 8 : t a r g e t = D o u b l e ( t a r g e t ) ;
1 9 : c o u t < < " T a r g e t : " < < t a r g e t < < e n d l ;
2 0 :
2 1 :
2 2 : t a r g e t = D o u b l e ( t a r g e t ) ;
2 3 : c o u t < < " T a r g e t : " < < t a r g e t < < e n d l ;
2 4 : r e t u r n 0 ;
2 5 : }
2 6 :
2 7 : i n t D o u b l e ( i n t t a r g e t )
2 8 : {
2 9 : r e t u r n 2 * t a r g e t ;
3 0 : }
O u t p u t : E n t e r a n u m b e r t o w o r k w i t h : 2 0

T a r g e t : 4 0
T a r g e t : 8 0
T a r g e t : 1 6 0

Analysis: On line 5, D o u b l e ( ) is declared to be an inline function taking an i n t parameter


and returning an i n t . The declaration is just like any other prototype except that the
keyword i n l i n e is prepended just before the return value. This compiles into code that is
the same as if you had written the following:
t a r g e t = 2 * t a r g e t ;

everywhere you entered

t a r g e t = D o u b l e ( t a r g e t ) ;

By the time your program executes, the instructions are already in place, compiled into the
OBJ file. This saves a jump in the execution of the code, at the cost of a larger program.

5.5. Recursive Functions


Most mathematical functions that we are familiar with are described by a simple formula.
For example, we can convert temperatures from Fahrenheit to Celsius by applying the
formula

- 19-
C = 5 (F-32) / 9
Given this formula, it is trivial to write a C++ function; with declarations and braces
removed, the one line formula above translates into one line C++ statement . Mathematical
functions are sometimes defined in a less standard form. For example we can define a
function f, valid on non negative integers, that satisfies:
f(0) = 0
f(x) = 2, f(x-1) +x2 for x>0, x e Z
From this definition,
f(3) = 2f(2) + 32
= 2f(2) + 9 now we should compute f(2) first.
f(2) = 2f(1) + 22
= 2f(1) + 4 now we should compute f(1) first.
f(1) = 2f(0) + 12
= 2f(0) + 1 now we should compute f(0) first.
f(0) = 0
ð f(1) = 2 (0) + 1
= 0 +1 = 1
ð f(2) = 2 (1) + 4
= 2 +4 = 6
=> f(3) = 2 (6) + 9
= 12 + 9 = 21
A function that is defined in terms of it self is called recursive. f(0) in the above function is
the value which is the function directly known with out resorting to recursion. Such case is
known as the base case. A recursive function without a base case is meaningless. When
writing recursive routines, it is crucial to keep in mind the four basic rules of recursion.
These are:
1. Base case: you must always have some Base case, which can be solved with out
recursion.
2. Making progress: for the cases that are to be solved recursively, the recursive call
must always be to a case that makes progress to ward a base case.
3. Design rule: Assume that all recursive calls work without fail. In order to find f(n)
recursively you can assume f(n-k) will work (k ³ 1)

- 20-
4. Compound interest rule: never duplicate work by solving the same instance of a
problem in separate recursive rule.
Some examples of recursive problems
a) The factorial function f(n) = n!
f(n) can be defined as:
f(N) = N x (N-1) x (N-2) x (N-3) x ..x 1 this is iterative defn

This function can be implemented both iteratively or recursively as


//iterative implementation
int factorial (int N)
{
int fact =1;
for(int i=1;i<=n; i++)
{
fact *=I;
}
return fact;
}
//recursive implementation
int factorial (int n)
{
if (n == 0) return 1;
return n*factorial(n-1)
}
b) Fibonacci progress :
is a sequence in which the ith term equals f(i) defined as

Some of the elements in the sequence are


1, 1, 2, 3, 5, 8, 13, 21, 34 .
The function can be implemented both iteratively and recursively. The recursive
implementation is shown bellow.
int i_th_fibonacci_element (int n)
{

- 21-
if (n == 1|| n==2) return 1;
else if n > 2
{
int val1 = i_th_fibonacci_element ( n-1);
int val2 = i_th_fibonacci_element ( n-2);
return (val1 +val2);
}
}
Some function cannot be implemented easily without recursion. Other functions,
which do admit both iterative and recursive solution are easier to understand in their
recursive form. So recursion is an essential tool for computer scientist.
However recursion is very expensive in terms of time complexity of a program so
that it is not generally advisable to use recursion to problems that is simple to
implement in iterative way. This is because of the time requirement to manipulate
stack at each function call.
Some more recursive problems and their implementation
C) The Euclidean algorithm
A positive integer d is a divisor of a larger integer n if n is some multiple of d; i.e. n
= k. d for some positive integer k
A positive integer is a common divisor of two larger integer n and m if it is a divisor
of both m & n. d is said to be greatest common divisor of two large integers m& n,
if it is a common divisor of m & n, and no other common divisor of m & n is greater
than d.
This can be denoted as d = gcd (m, n).
It might seem that finding gcd of large integers could be very tedious and time
consuming. But fortunately the ancient Greek scientist Euclid discovered a clever
recursive algorithm as follow.

int gcd (int m, int n)


{
if (m == n) return n;
else if (m > n) return gcd (n, m);
else return gcd (n-m, m);

- 22-
}
D) Binary Search
Binary search for an element x in sorted array A[] looks at the middle of the array. If that is
not x (the middle element of A x) then it continues the search in the half that potential
could hold x. Assuming the array is sorted in ascending order, the potential half array is the
left array if the middle is larger than x other wise the right the potential list to hold x. The
process contributes this recursive step until either x is found or the sub array is empty.
What should be returned in the index of the array that hold x if it founds or -1.
Implementation
int find (float*a, int start, int stop, float x )
{
if (start > stop) return -1;
int mid = (start + stop) / 2;
if (x == a[mid] return mid;
if (x <a[mid] return find (a, start, mid -1, x );
else return find (a, mid +1, start , x );
}
The call from other program to this function may look like
index = find(list, 0, size-1);
e) The tower of Hanoi
A classic example to demonstrate the power of recursion in problem solving is the tower of
Hanoi puzzle. In this puzzle we are given three pegs labeled A, B and C. Initially a tower of
N disk of different sizes is stacked on peg A in order of decreasing size. That is, the largest
disk is on the bottom, and the smallest disk is on the top of the tower as shown bellow

A B C
The objective is to transfer the entire disks from peg A to one of the other pegs, say C
moving only one disk at one time, never moving the larger disk on the top of smaller disk.
The solution follows a simple procedure.
if N = 1 then just move it to destination peg. Otherwise

- 23-
1- Reduce the problem that say move the top N-1 disk from peg A to B using C .
2- Move the Nth disk (which is the largest) from peg A to C.
3- Now move the N-1 disks from B to C using A. And this will tell us what to do for
any N.
The implementation is as follows:
#include <iostream.h>
#include <conio.h>
void Form(int N, char pegA ,char pegB , char pegC )
{
if (N==1)
cout<<"move top disk on peg "<<pegA<<" to peg "<<pegC<<endl;
else
{
Form(N-1,pegA,pegC,pegB);
cout<<"move top disk on peg "<<pegA<<" to peg "<<pegC<<endl;
Form(N-1,pegB,pegA,pegC);
}
}

int main ()
{
char F;
int N;
cout<<"How many disks ?=====>";cin>>N;
Form(N,'A','B','C') ;
getch () ;
return 0;
}

- 24-

You might also like