Chapter 8 Detailed Class Notes Updated
Chapter 8 Detailed Class Notes Updated
Value-returning functions – 1. receive data through its argument list 2. compute a single function value
3. returns this function value for the calling code.
The caller invokes (calls) a value-returning function by using its name and argument list in an expression.
Ex. y = 3.8 * sqrt (x);
A void function – 1. does not return a value 2. not called from within an expression but a complete
standalone statement. Ex. get function associated with istream and ifstream – [Link](inputChar);
In this chapter, we will concentrate exclusively on creating our own void functions. Chapter 9 will be
concerning our writing of value-returning functions.
We have been designing programs as collections of modules. Many of them are naturally implemented
as user-defined void functions.
Let’s change our previous mindsets since we are moving from simple programs to larger and more
complex programs which may involve a team of programmers to work collectively to implement and
support.
While you can code any module as a function, the decision should be based on whether the program is
easier to be understood as a result.
If a module has (1) line then of course not. It would just over complicate it to write it as a function.
Adversely, if the module has many lines of code then simplify it by writing it as a function.
Implement a short module as a function if it will be used in several places within a program
Coding it in (1) place and calling it from many places yield better design because
1. less opportunity for errors or mistakes from recoding it multiple times
2. more efficient and easier to update that module or object of code. Update in one location or
conduct a search.
Recent Industry platforms that my associates within Corporate America’s fortune 500 companies are
using: Microsoft 365 PowerApps, Dell’s Boomi LowCode NoCode – all object-oriented coding modules.
Previously and up until now, our modules have simply been a group of statements that has access to all
of the values in a program. This works for small programs but not when we have large programs with
many modules.
In large complex programs, it is a bad idea to allow every module to access every value. PRIVACY,
Security, coordination of possible duplicate programmer identifiers, etc. are a concern. For this
purpose, the module’s design aspect needs an interface.
Analogy – within a house people leave doors open but, in a hotel, doors to each room should be locked.
Designing Interfaces
We consider a module as a separate block within a design whose implementation details are “hidden”
(walled-off) from view.
Postcondition: A message has been printed indicating an appropriate activity given temperature
temp
Implementation
From the external perspective, as long as you know what a module does and how to call it, you can use
the module without knowing how it accomplishes its task. ex. sqrt – didn’t know yet used it.
A module’s interface is the formal description of what the subprogram does and how it is invoked or
how we communicate with it.
Hiding a modules’ implementation is called encapsulation. It is hidden in a separate block within a
formally specified interface.
Advantages of Encapsulation
1. no concerns or worries that it will accidentally access the values in other modules or that other
modules will be able to change its values
2. we can make internal changes to a module, as long as the interface remains the same
One way to specify the interface to a module is to write down its purpose (its precondition and
postcondition) and the information it takes and returns. This documentation is important when working
within a team so that we can hand it to someone who could implement the module for us.
To define the mechanism for communicating with the module, we make a list of the below:
1. Incoming values that the module receives from the caller.
2. Outgoing values that the module produces and returns to the caller.
3. Incoming/outgoing values – values that the caller has that the module changes (receives and
returns)
Data flow is the direction of flow of information between the caller and a module through each
parameter.
Now, let’s start coding C++ modules since we know how to design a module for implementation as a
function!
Writing Modules as Void Functions
1. a void function looks like a main function except the function heading uses void rather than int
as the data type of the function.
2. it doesn’t have a return 0; because remember a void function doesn’t return a value to its caller.
Example, does not have parameters. Friend is returning from a long trip and we will write a program to
print “Welcome Home!” message. p. 349
int main ()
void nameofvoidfunction (parameter)
Students and Instructor typed this program during class. You can use this program as one of your many
programs to post within your Weekly Discussion Board posts for a grade.
Remember, just like other C++ identifiers, the name of a function cannot include blanks. C++ function
definitions can appear in any order.
function prototypes – here are before the main function – void Print2Lines(); and void Print4Lines()
This is necessary because identifiers must be declared before using them. Comments are included to
describe the functions so main function makes sense. →Quick Check Questions on p. 353
8.2 An Overview of User-Defined Functions
More important points of function construction and learn how to use them.
Review the previous chapters: When a function call is encountered within the main function, control
passes to the 1st statement in that function’s body. All statements are then executed in logical order
within that function’s body. After it is all executed then control is passed back to main to the next
statement following that function’s call.
Because functions alters the order of execution, functions are considered control structures.
Let’s rewrite the previous program to be more efficient because the 2 void functions are so similar that
we don’t need both. They merely print a different number of lines of asterisks.
• Reminder, items listed in the call to a function are the arguments. which constitute the external
view of a function’s interface.
• Argument – a variable or expression listed in a call to a function. (When you invoke a call)
• Parameter – a variable declared in a function heading (and prototype or just above the body )
(This is a must understand in order to understand the rest of the semester.)
Parameters provide identifiers within the function by which we can refer to the values supplied through
the arguments. The arguments of the functions are 2 and 4 within the above program. Parameters in
the PrintLines function is named numLines.
Below is another version of the main function, just to show that the arguments can be variables instead
of constants.
int main ()
{
int lineCount;
lineCount = 2;
PrintLines (lineCount);
cout << “ Welcome Home! “ << endl;
lineCount = 4;
PrintLines(lineCount);
return 0;
}
In this version, each time main calls PrintLines, a copy of the value in lineCount is passed to the function
to initialize the parameters numLines. As you can see, the argument and the parameter (numLines) can
have different names.
Again, a function can be called from many places. If a task must be done repetitively then a function is
appropriate to avoid repetitive coding.
If more than one argument is passed to a function, the argument and parameters are matched by their
relative positions in the two lists. For example, if PrintLines are to print another character and not only
asterisks then the code would be….
void PrintLines (int numLines, char whichChar) - (declaring the prototype above main)
PrintLines (3, ‘#’); (could be the call from within the main function – the arguments)
the first argument, 3, is matched with numLines because it is the 1st parameter. Likewise, the 2nd
argument, ‘#’, is matched with the 2nd parameter, whichChar.
FunctionName (Argument);
• The argument list is optional, but the parentheses are required even if the list is empty.
• If the list includes two or more arguments, you must separate them with commas.
Syntax template for ArgumentsList:
When a function call is executed, the arguments are passed to the parameters according to their
positions, left to right, and control is then transferred to the first executable statement in the function
body. When the last statement in the function has executed, control returns to the point from which
the function was called.
Function Definition
a function declaration that includes the body of the function. Examples:
The NewWelcome program contains (3) function declarations. The first one (the statement
documented as the function prototype) does not include the body of the function. The other two -
main and PrintLines included the bodies of the function so they are function definitions.
C++ Rule → You can declare an item as many times as you wish, but you can define it only once.
For Example, in the NewWelcome program, we could include many function prototypes for PrintLines
but only (1) function definition is allowed.
No body is included and a semicolon terminates the declaration. The parameter list is optional, to allow
for parameterless functions. If the parameter list is present, it has the following form:
ParamentList (in a Function Prototype)
The ampersand (&) attached to the name of the data type is optional and has a special significance what
we will cover in a later chapter.
In a function prototype, the parameter list must specify the data types of the parameters, but their
names are optional. For example,
Sometimes adding the names is useful for documentation purposes to supply names for the parameters,
but be aware that the compiler ignores them.
Here is the Syntax Template for a Function Definition – specifically for a Void Function:
Notice that the function heading does not end in a semicolon the way a function prototype does.
Putting a semicolon at the end of the line will generate a syntax error.
The syntax of the parameter list differs slightly from that of a function prototype in that you must
specify the names of the parameters. Also, its our style preference (but not a C++ language
requirement) to declare each parameter on a separate line. For example, ….
All functions are global variables because they are declared outside of main
As far as the calling code is concerned those local variables (for the function called) do not exist within
the environment where the function is called. In fact, if you tried to print the contents of a local variable
from another function, a compile-time error such as UNDECLARED IDENTIFIER could occur. For example,
the local variable, count, in the NewWelcome program was declared within the PrintLines function.
Unlike local variables, global variables are declared outside of all the functions in a program. (more
about this in Chapter 9).
• Local variables occupy memory space only while the function is executing. At the moment, the
function is called, memory space, is created for its local variables.
• When the function returns, its local variables are destroyed. (We will see an exception to this rule in Chapter 9).
Therefore, every time the function is called, its local variables start out with their undefined.
• Because every call to a function is independent of every other call to that same function, you
must initialize the local variables within the function itself.
• Also, because local variables are destroyed when the function returns, you cannot use them to
store values between calls to the function.
This code illustrates each of the parts of the function declaration and calling mechanism:
#include <iostream>
using namespace std;
The Void Function does not return a function value. Control returns from the function when it “falls off”
the end of the body after the last statement is executed.
Subprograms or void function can either not have a return statement - OR - a return statement like this
return;
This statement is valid only for void functions. As you saw in the NewWelcome program, the PrintLines
function simply prints some lines of asterisks and then returns.
• It (return;) can appear anywhere in the body of the function; it causes control to exit the
function immediately and return to the caller. For example,
In this example, there are (2) ways for control to exit the function. (You tell me → “How is this”?) At
function entry, the value of n is tested. If it is > 50 function prints a message and returns immediately
without executing any more statements. If n is less than or = to 50, the IF statements then clause is
skipped and control proceeds to the assignment statement. After the last statement, control returns
to the caller.
This is just a different option for you as a programmer. Use it if it makes more sense to you but use it
sparingly = recommendation. It allows for multiple exits for a function.
8.4 – Parameters
When a function is executed, it uses the arguments give to it in the function call. How is this done? It
depends on the nature of the parameters.
• With a value parameter, which is declared without an (&) ampersand at the end of the data type
name, the function receives a copy of the argument(s)’ value.
• With the reference parameter, which is declared by adding an ampersand (&) to the data type
name, the function receives the location (memory address) of the caller’s argument.
Example, function heading with a mixture of reference and value parameter declarings.
with simple data types (int, char, float … ) – a value parameter is the default (assumed) kind of
parameter.
(Pay close attention from here out so that you don’t waste time understanding the content and need to
spend more time reviewing it on your own later. Attention, look, watch, listen ….. If I get to step 8 and
you ask me to re-explain all of the previous steps then I will ask you to read this again or read the book.)
The parameter numLines is a value parameter because its data type name doesn’t end with &. If the
function is called using an argument lineCount,
PrintLines (lineCount);
then the parameter numLines receives a copy of the value of lineCount. At this moment, there are two
copies of the data – one in the argument lineCount and one in the parameter numLines. If a statement
inside the PrintLines function were to change the value of numLines, this change would not affect the
argument lineCount (remember, there are two copies of the data). As you can see, using value
parameters help us avoid unintentional changes to arguments.
Because value parameters are passed copies of their argument, anything that has a value may be passed
to a value parameter. This includes constants, variables, and even arbitrarily complicated expressions.
(The expression is simply evaluated and a copy of the result is sent to the corresponding value
parameter.) For the PrintLines function, the following function calls are all valid:
PrintLines (3);
PrintLines (lineCount);
PrintLines (2 * abs (10 – someInt) );
There must be the same number of arguments in a function call as there are parameters in the function
heading. Also, each argument should have the same data type as the parameter in the same position.
Notice how each parameter in the following example is matched to the argument in the same position
(the data type of each argument is what you would assume from its name):
Function heading: void ShowMatch (float num1, int num2, char letter)
If the matched items are not of the same data type, implicit type coercion takes place. For example, if a
parameter is of type int, an argument that is a float expression is coerced to an int value before it is
passed to the function. As usual in C++, you can avoid unintended type coercion by using an explicit
type cast or, better yet, by not mixing data types at all.
As it has been stressed, a value parameter receives a copy of the argument and, therefore, the caller’s
argument cannot be accessed directly or changed. When a function returns, the contents of its value
parameters are destroyed, along with the contents of its local variables. The difference between value
parameters and local variables is that the values of local variables are undefined when a function starts
to execute, whereas value parameters are automatically initialized to the values of the corresponding
arguments.
Because the contents of value parameters are destroyed when the function returns, they cannot be
used to return information to the calling code. What if we do want to return information by modifying
the caller’s arguments? We must use the second kind of parameter available in C++: reference
parameter. Let’s look at these in more detail now.
Reference Parameters
A reference parameter is one that you declare by attaching an ampersand to the name of its data type.
It is called a reference parameter because the called function can refer to the corresponding argument
directly. Specifically, the function is allowed to inspect and modify the caller’s argument.
When a function is invoked using a reference parameter, it is the location (the memory address) of the
argument – not its value – that is passed to the function. Only one copy of the information exists, and it
is used by both the caller and the called function. When a function is called, the argument and the
parameter becomes synonyms for the same location in memory. When a function returns control to its
caller, the link between the argument and the parameter is broken. They are synonymous only during a
particular call to the function. The only evidence that a matchup between the two every occurred is
that the contents of the argument may have changed. See below → Using a Reference Parameter to Access an Argument
When flow of control is in the main function,
temperature can be accessed as shown by the arrow.
temperature
int main() } Variable temperature
declared by main function
temperature
int main()
Whatever value is left by the called function in this location is the value that the caller will find there.
You must be careful when using a reference parameter, because any change made to it affects the
argument in the calling code. Here is an example of a heading and a call:
Function heading: void ShowMatch (float& num1, int num2, char& letter)
Another important difference between value and reference parameters relates to matching arguments
with parameters. With value parameters, it was stated that implicit type coercion occurs (the value of
the argument is coerced, if possible, to the data type of the parameter). In contrast, reference
parameters require that the match items must have exactly the same data type.
Earlier in this chapter, we discussed documenting data flow direction in modules. Function parameters
corresponding to Out and In/out module parameters must have an ampersand to In parameters.
Value parameters - If a new value is assigned then its value will change. However, it
won't affect the original argument's value. Value parameters have two copies of data.
If a new value is assigned to a reference then the location of the original argument will
change. Reference parameters only have 1 copy of its data.
In this DoThis function, the first parameter is a value parameter, so any expression is allowed as the
argument. The second parameter is a reference parameter, so the argument must be a variable name.
The statement
ArgumentList
Expression , Expression ……
Keep in mind, however, that Expression is restricted to a variable name if the corresponding parameter
is a reference parameter.
For example, suppose we had written the modification to the LoanCalculator program as follows. Can
you spot the error?
int main ()
{
…..
GetRest (monthlyInterest, numberOfYears);
numberOfPayments = numOfYears * 12;
DeterminePayment (monthlyInterest, loanAmount,
numberOfPayments, payment);
….
}
The argument list in the last function call matches the corresponding parameter list in its number and
type of arguments, so no syntax error message would be generated. However, the output would be
wrong because the first two arguments are switched. If a function has two parameters of the same data
type, you must be careful that the arguments appear in the correct order.
Later in the textbook, we will learn how to write multifile programs and hide implementations
physically. In the meantime, conscientiously avoid writing code that depends on the internal workings
of a function.
The precondition is an assertion describing everything that the function requires to be true at the
moment when the caller invokes the function. The postcondition describes the state of the program at
the moment when the function finishes executing.
You can think of the precondition and the postcondition as forma a contract. The contract state that if
the precondition is true as the function entry, then the postcondition must be true at the function exit.
The caller is responsible for ensuring the precondition, and the function body must ensure the
postcondition. If the caller fails to satisfy its part of the contract (the precondition), the contract is off;
the function cannot guarantee that the postcondition will be true.
In the preceding example, the precondition warns the caller to make sure the sum has been assigned a
meaningful value and that count is positive. If this precondition is true, the function guarantees it will
satisfy the postcondition. If count isn’t positive when PrintAverage is invoked, the effect of the module
is undefined. (For example, if count equals 0, the postcondition surely isn’t satisfied – any code that
implements this module crashes!)
Sometimes the caller doesn’t need to satisfy any precondition before calling a function. In this case, the
precondition can be written as the value true or simply omitted. In the following example, no
precondition is necessary:
Read pages 387 – 389 for more information concerning Testing and Debugging and especially read the
Summary on page 390.
Review and challenge yourself with the end of the chapter Exam Preparation Exercises, the
Programming Warm-up Exercises, and the Programming Problems.