Unit 6

advertisement
Chapter 6: Modular Programming
In Chapter 3, we learned the basics of writing functions for a
program. We discussed how functions could be used to
correspond to the individual steps in a problem solution. We
have been using functions with no parameters and no return
value. We have also written functions that were passed input
parameters and returned a single output, the return value. In this
chapter we will expand upon our knowledge and learn how to
use functions to create a program system – an arrangement of
separate modules that pass information from one to the other.
6.1 Value and Reference Parameters
So far, we know how to write functions that return a single
result or value. Now, we will learn how functions can be used
to return multiple values.
Call-by-Value and Call-by-Reference Parameters
As we have seen, the method of calling a function and passing
values to it is referred to as a function call by value.
Calling a function by value is a distinct advantage of C++. It
allows functions to be written as independent entities without
concern that altering an argument or variable in one function
may inadvertently alter the value of a variable in another
function. At no time does the called function have direct access
to any variable contained in the calling function.
There are situations, however, when it is convenient to alter this
approach and give a function direct access to variables of its
1
Chapter 6: Modular Programming
calling function. To do this requires that both the sending and
receiving arguments reference the same storage locations in
memory. Once the called function can reference the storage
locations of a passed argument it can directly access and change
the value stored there. When a reference is passed to a function,
it is referred to as a call by reference.
Passing and Using References
From the sending side calling a function and passing a reference
is exactly the same as calling a function and passing a value. In
this case, the function needs to be able to declare two arguments
that can store references.
For example, the function prototype:
void newval (float &, float &);
and the function definition header:
void newval (float &num1, float &num2)
and using these function prototype and definition header in a
program:
Example: Program 6-1
#include <iostream>
using namespace std;
2
Chapter 6: Modular Programming
int main( )
{
float firstnum, secnum;
// prototype - accept two references
void newval(float &, float &);
cout << "Enter two numbers: ";
cin >> firstnum >> secnum;
cout << "\nThe value in firstnum is: " << firstnum << '\n';
cout << "The value in secnum is: " << secnum << "\n\n";
newval(firstnum, secnum); // call the function
cout << "The value in firstnum is now: "
<< firstnum << '\n';
cout << "The value in secnum is now: " << secnum << '\n';
return (0);
}
void newval(float & num1, float & num2)
{
cout << "The value in num1 is: " << num1<< '\n';
cout << "The value in num2 is: " << num2<< "\n\n";
num1= 89.5;
num2= 99.5;
return;
}
3
Chapter 6: Modular Programming
Note: The formal arguments num1 and num2 do not store
copies of the values in firstnum and secnum, but directly
access the locations in memory set aside for these two
arguments.
The equivalence between actual calling arguments and formal
function arguments provides the basis for returning multiple
values from within a function.
Example:
void calc(float num1, float num2, float num3, float &total, float &product)
{
total = num1 + num2 + num3;
product = num1 * num2 * num3;
}
Program 6-2:
#include <iostream>
using namespace std;
void main(void)
{
float firstnum, secnum, thirdnum, sum, product;
void calc(float, float, float, float &, float &); // prototype
cout << "Enter three numbers: ";
cin >> firstnum >> secnum >> thirdnum;
4
Chapter 6: Modular Programming
// function call
calc(firstnum, secnum, thirdnum, sum, product);
cout << "\nThe sum of the numbers is: " << sum;
cout << "\nThe product of the numbers is: " << product;
cout << endl;
return;
}
void calc(float num1, float num2, float num3,
float &total, float &product)
{
total = num1 + num2 + num3;
product = num1 * num2 * num3;
return;
}
// Input
// Output
In-Class Exercise:
Write function that accepts a real number as input and returns it
whole and fractional parts as output. For example, if the input is
5.32, the function outputs should be the integer 5 and the real
value 0.32.
Test your function in a program that takes its input from the
user.
5
Chapter 6: Modular Programming
void Functions Can Return Results
Even though we declared the calc( ) as a void function, it can
still return results to the calling functions by using output or
reference parameters. By declaring this function as type void,
we are only telling the compiler that we will not be using the
return statement to return a value to the calling function.
When to Use a Reference or a Value Parameter
How do we decide when to use a reference parameter or a value
parameter?
1.
If the information passed into a function does not have to
be returned or passed out of the function, then the formal
parameter used for that information should be a value or an
input parameter.
2.
If the information needs to be returned to the calling
function through a parameter (and not a return statement),
then the formal parameter used for that information must
be a reference or an output parameter.
3.
If the information is to be passed into a function, possibly
modified, and a new value returned, then the formal
parameter used for that information must be a reference or
an input/output parameter (or inout parameter).
Note: C++ does not distinguish between output parameters and
input/output parameters. Both must be defined as
reference parameters in both the prototype and the
function header by using the ampersand (&) symbol.
6
Chapter 6: Modular Programming
This will cause the address of the corresponding actual
argument to be stored in the data area of the called
function. It is assumed that the argument used in the
function call for an input/output parameter will contain
some meaningful data before the function is called and
executed.
Argument/Parameter List Correspondence Revisited
In Section 3.5, we discussed argument/parameter list
correspondence. We used the acronym not to summarize the
constraints on the number, order and type of input arguments
and how they must agree. The rules are repeated below with
one addition (as quoted from your book):
1.
Number: The number of actual arguments used in a call to
function must be the same as the number of formal
parameters listed in the function prototype.
2.
Order: The order of arguments in the lists determines the
correspondence. The first must correspond to the first, the
second to the second, and so on.
3.
Type: Each actual argument must be of a data type that
can be assigned to the corresponding formal parameter
without loss of information.
4.
For reference parameters, an actual argument must be a
variable. For value parameters, an actual argument may be a
variable, a constant or an expression.
7
Chapter 6: Modular Programming
In-Class Exercise:
Write a function that accepts an input argument consisting of
two words with a space between them and returns each work
through its two output parameters. All three parameters should
be type string.
Use the following main( ) to call test your function:
#include <iostream>
#include <string>
using namespace std;
int main()
{
char input[50]; // Input array - two words separated by
space
string inString;
string firstWord;
// Output string
string secondWord; // Output string
cout << "Enter two words separated by a space: ";
cin.getline(input, sizeof(input), '\n');
inString = input;
// Assign array value to string
// Insert function call here.
cout << "The first word is: " << firstWord << endl
<< "The second word is: " << secondWord << endl;
return (0);
8
Chapter 6: Modular Programming
}
9
Chapter 6: Modular Programming
Inline Functions
Calling a function places a certain amount of overhead on a
computer. This consists of placing argument values in a
reserved memory region that the function has access to (stack),
passing control to the function providing a reserved memory
location for any returned value, and finally returning to the
proper point in the calling program. Paying this overhead is
well justified when a function is called many times.
For small functions that are not called many times, however, the
overhead for passing and returning values may not be
warranted.
Telling the C++ compiler that a function is inline causes a copy
of the function code to be placed in the program at the point
where the function is called.
To accomplish this simply requires placing the reserved word
inline before the function name and defining the function before
any calls are made to it.
The advantage of using an inline function is an increase in
execution speed. There is no execution time loss due to the call
and return overhead required by a non-inline function.
The disadvantage is the increase in program size when an inline
function is called repeatedly. Each time an inline function is
referenced the complete function code is reproduced and stored
as an integral part of the program. A non-inline function,
however, is stored in memory only once.
10
Chapter 6: Modular Programming
EXAMPLE: Program 6-3
#include <iostream>
using namespace std;
inline double tempvert(double in_temp)
{
return( (5.0/9.0) * (in_temp - 32.0) );
}
int main( )
{
int count;
double fahren;
// start of declarations
for (count = 1; count <= 4; count++)
{
cout << "\nEnter a Fahrenheit temperature: ";
cin >> fahren;
cout << "The Celsius equivalent is "
<< tempvert(fahren) << endl;
}
return (0);
}
11
Chapter 6: Modular Programming
6.2 Functions with Output and Inout Parameters
In the previous section, we reviewed examples of functions
which accepted input parameters and returned the results
through output parameters. In this section, we will review
examples of functions that have only output or inout
(input/output) parameters.
The swap ( ) function
In this example a function called swap( ) will be written for
exchanging the value of two of the main function variables.
One way of doing this is by using reference variables. This is
an example of inout or input/output parameters. There are
three steps involved in this function:
1. Store the first argument's value in a temporary location.
2. Store the second argument's value in the first variable.
3. Store the temporary value in the second argument.
void swap (float &num1, float &num2)
{
float temp;
temp = num1; //step 1
num1 = num2; //step 2
num2 = temp; // step 3
}
12
Chapter 6: Modular Programming
The Complete Program: Program 6-4
#include <iostream>
using namespace std;
void main(void)
{
float firstnum = 20.5, secnum = 6.25;
// function prototype - receives 2 references
void swap(float &, float &);
cout << "The value stored in firstnum is: "
<< firstnum << "\n";
cout << "The value stored in secnum is: "
<< secnum << "\n\n";
// call the function with references
swap(firstnum, secnum);
cout << "The value stored in firstnum is now: "
<< firstnum << "\n";
cout << "The value stored in secnum is now: "
<< secnum << "\n";
return;
}
13
Chapter 6: Modular Programming
void swap(float &num1, float &num2)
{
float temp;
temp = num1;
num1 = num2;
num2 = temp;
// save num1's value
// store num2's value in num1
// change num2's value
return;
}
Two cautions:
1. The reference arguments cannot be used to change constants.
For example: swap( 20.5, 6.5) does not change the values
of these constants.
2. The reference arguments should only be used in restricted
situations that actually require multiple return values, such as
the swap( ) function. The calc( ) function in Program 6-2,
while useful for illustrative purposes, could also be written as
two separate functions, each returning a single value.
14
Chapter 6: Modular Programming
The getFrac( ) function
In this example a function called getFrac( ) will be written
which actually reads its data items from the keyboard. This is
an example of a function using output parameters only.
EXAMPLE: Program 6-4
#include <iostream>
using namespace std;
void getFrac(int&, int&);
int main()
{
int num,
denom;
// Function prototype
// input - fraction numerator
// input - fraction denominator
cout << "Enter a common fraction "
<< "as 2 integers separated by a slash: ";
getFrac(num, denom);
cout << "Fraction is " << num
// There is an error
<< " / " << denom << endl; // in your book here
return (0);
}
15
Chapter 6: Modular Programming
// Reads a fraction
void getFrac(int& numerator,
// OUTPUT
int& denominator) // OUTPUT
{
char slash;
// temporary storage for slash
cin >> numerator >> slash >> denominator;
return;
}
In-Class Exercise:
Write a function called displayFrac( ) that displays a common
fraction given its numerator and denominator as input
arguments.
Modify Program 6-4 to use your new function.
16
Chapter 6: Modular Programming
The order( ) function
In this next example, multiple calls will be made to a function
called order( ) which uses inout parameters. The order( )
function stores the smaller of its two arguments in its first actual
argument and the larger is stored in its second actual argument.
The main( ) function will call the order( ) function three times to
sort three data values in increasing order.
EXAMPLE: Program 6-5
#include <iostream>
using namespace std;
void order(float&, float&);
// INOUT - numbers to sort
int main( )
{
// user input - numbers to sort
float num1, num2, num3;
// Read 3 numbers
cout << "Enter 3 numbers to sort: ";
cin >> num1 >> num2 >> num3;
// Sort them
order(num1, num2);
order(num1, num3);
order(num2, num3);
// order data in num1 & num2
// order data in num1 & num3
// order data in num2 & num3
17
Chapter 6: Modular Programming
// Display results
cout << "The three numbers in order are:" << endl;
cout << num1 << " " << num2 << " " << num3 << endl;
return (0);
}
void order(float& x, float& y)
{
float temp;
// storage for number in x
// Compare x and y, exchange values if not in order
if (x > y)
{
// exchange values in x and y
temp = x;
// store old x in temp
x = y;
// store old y in x
y = temp;
// store old x in y
}
return;
}
18
Chapter 6: Modular Programming
6.3 Stepwise Design with Functions
Passing information into and from functions improves the
ability of the programmer to solve problems. When designing a
program, we separate the primary problem of the program into
subproblems. This allows the programmer to modularize the
program into individual subproblems or pieces. If any solution
to a single subproblem cannot be written easily in a few C++
statements, it makes sense to code it as a function.
CASE STUDY: General Sum and Average Problem
Problem:
We need create code that can be used to
accumulate a sum and average a list of data
values using functions. These tasks are required
in many programs; therefore, we need to design
a general set of functions that can be reused in
other programs and, later on, when we design
actual classes.
Analysis:
1.
This is something we have done several times
already. Let’s analyze the requirements.
What are the general steps involved to accomplish this
task?
19
Chapter 6: Modular Programming
2.
What are the data requirements?
a. Problem Input:
b. Problem Output:
3.
What formula(s) are needed?
Design:
At this stage, we need to develop the algorithm
necessary to accomplish our task and document
the data flow between the main problem and each
of its subproblems.
Initial Algorithm:
1. Read the number of items.
2.
Read the data items and compute the sum of the data.
3.
Compute the average of the data.
4.
Print the sum and the average.
20
Chapter 6: Modular Programming
In-Class Exercise:
Develop a structure chart that documents this initial algorithm
and the data flow between the main( ) function and each of the
subproblems or functions.
Implementation:
Using the structure chart we developed in the design
phase, we can now write the main( ) function before
we develop the algorithms involved for any of the
steps or subproblems.
1.
What data elements or variables are needed in main( )?
2.
Move the initial algorithm into main( ) as comments.
3.
Code each step in-line (as part of the code) or as a
function call.
21
Chapter 6: Modular Programming
In-Class Exercise:
Implement the above steps in a source code file. At this point,
we need only include the necessary prototypes for our functions.
You should be able to compile this code. (Do not build or link it
since we have not developed the functions yet.)
Stepwise design of the functions
At this stage, we need to repeat the above steps for each of the
three functions as prototyped and called in the above
implementation:
1.
2.
3.
float computeSum(int);
float computeAverage(int, float);
void printSumAve(int, float, float);
I. Analysis for computeSum( )
Function Interface --Input parameters: int numItems // number of items
Output parameters: none
Return value:
the sum (float) of data items
processed
Local Data:
float item
float sum
int count
// each data item as read in
// accumulates the sum of data read in
// number of items processed
22
Chapter 6: Modular Programming
Design for computeSum( )
Need a loop to control the reading of the data items. We
already know the number of items so we can use a
count-controlled loop.
Initial Algorithm:
1. Initialize sum to 0.
2. For each value of count (count = 0 ; count < numItems)
a. Read in the data item.
b. Add the data item to sum.
3. Return sum to the calling function.
II. Analysis for computeAverage( )
Function Interface --Input parameters: int numItems // number of items
float sum
// sum of all items
Output parameters: none
Return value:
the average (float) of data items
Design for computeAverage( )
Initial Algorithm:
1. If the number of items is less than1
a. Display “invalid number of items” message.
b. Return value of 0.
2. Return value of the sum divided by numItems.
23
Chapter 6: Modular Programming
III. Analysis for printSumAve( )
Function Interface --Input parameters: int numItems // number of items
float sum
// sum of all items
float average // average of all items
Output parameters: none
Return value:
none
Design for printSumAve( )
Initial Algorithm:
1. If the number of items is positive ( > 0)
a. Display the number of items, the sum, and the
average of the data.
Else
a. Display “invalid number of items” message.
In-Class Exercise:
Implement the function definitions in your source code file.
Test your program.
Issues of Program Style
Use of Functions for Relatively Simple Algorithm Steps
Although some functions are quite short and would be easier to
include as in-line code, it is better to use a separate function.
The use of functions provide some of the following benefits:
24
Chapter 6: Modular Programming
1.
2.
3.
Help keep details of code separate and hidden from those
who do not need to see the details.
Make your program easier to debug, test, and even modify.
Allow possibility of the reuse of the function at some other
time.
From now on, our main( ) functions should primarily consist of
a sequence of function calls.
Cohesive Functions
Our computeSum( ) function only performs one task. It
computes the sum of the data items as they are read in.
Functions that perform a single operation are called functionally
cohesive. It is a good programming style to write such singlepurpose, highly cohesive functions. These functions are
relatively compact, easy to read, write and debug.
In-Class Exercise:
Design and implement an algorithm for readNumItems( ) that
uses a loop to ensure that the user enters a positive value for the
numItems variable. The loop should continue reading numbers
until the user enters a positive number.
Modify the previous exercise to use this function instead of the
code inside main( ).
25
Chapter 6: Modular Programming
6.4 Using Objects with Functions
There are two ways that you can use functions to modify objects
in C++:
1.
You can use dot notation to apply a member function to
an object. The member function may modify one or
more data attributes of the object to which it is applied.
2.
You can pass an object as an argument to a function.
The following example uses both methods.
moneyToNumberTest.cpp (from textbook)
#include <string>
#include <iostream>
using namespace std;
// Function prototype
void moneyToNumberString(string&);
int main()
{
string mString;
// input - a "money" string
cout << "Enter a dollar amount with $ and commas: ";
cin >> mString;
moneyToNumberString(mString);
cout << "The dollar amount as a number is " << mString
<< endl;
return 0;
}
26
Chapter 6: Modular Programming
// Removes the $ and commas from a money string.
void moneyToNumberString
(string& moneyString) // INOUT - string w/poss. $ and commas
{
// Local data . . .
int posComma;
// position of next comma
// Remove $ from moneyString
if (moneyString.at(0) == '$')
moneyString.erase(0, 1);
else if (moneyString.find("-$") == 0)
moneyString.erase(1, 1);
// Starts with $ ?
// Remove $
// Starts with -$ ?
// Remove $
// Remove all commas
posComma = moneyString.find(",");
while (posComma >= 0 &&
posComma < moneyString.length())
{
moneyString.erase(posComma, 1);
posComma = moneyString.find(",");
}
} // end moneyToNumberString
// Find first ,
// posComma valid?
// Remove ,
// Find next ,
In-Class Exercise:
Write a function doRemove( ) that removes the first occurrence
of a substring (an input argument) from a second argument
string (input/output argument).
Write a main( ) function to test your new function.
27
Chapter 6: Modular Programming
6.5 Debugging and Testing a Program System
The possibility of errors increase as the size of your programs or
program system grows. By keeping each function to a
manageable size keeps this increase to a minimum. Testing and
debugging each function is also much easier. By writing a large
program as a set of independent functions, you can simplify the
overall programming process.
You can also simplify the testing and debugging process by
testing in stages as your program evolves. There are two kinds
of testing used: top-down testing and bottom-up testing. You
should use a combination of these methods to test your program
and its functions.
Top-Down Testing and Stubs
When you are part of a programming team (or even if working
alone), you will find that not all functions will be ready at the
same time. To simplify the debugging process, it is desirable,
also, to test your program as it evolves rather than waiting for it
to be completed.
You can begin by testing the overall flow of control between the
main program and its level-1 functions that are complete.
Level-1 functions are those functions that are called directly
from main( ). The process of testing the flow of control
between a main( ) function and its subordinate functions is
called top-down testing.
28
Chapter 6: Modular Programming
Because main( ) calls all level-1 functions, we need to provide a
substitute for all functions that are not yet coded. This
substitute is called a stub – a function with a heading and a
minimal body that is used to test the flow of control. The stub
will test the basic functionality of the call to the function and the
return statement. The body of the stub should include a simple
cout that displays a message identifying the function being
executed. It should also assign simple values to any outputs.
Stub for function computeSum( ):
// Computes sum of data – stub
float computeSum(int numItems) // IN – number of data items
{
cout << “Function computeSum( ) entered” << endl;
return 100.0;
// arbitrary value returned
}
Bottom-Down Testing and Drivers
When a function is completed, you can substitute it for its stub
in your program. But, before making it part of the large
program, you will normally want to test the new function itself.
By testing the function independently, it will be easier to locate
and correct any errors, since you will not be dealing with a
complete program system. This independent test of an
individual function is called a unit test. We can perform a unit
test by writing a short driver function to call it.
A driver function is a main( ) function that is used to test the
functionality of a single function. It does not need to be
complex; rather, it should contain only those declarations and
executable statements that are necessary to test a single
29
Chapter 6: Modular Programming
function. It should begin by reading or assigning values to all
input arguments and to input/output arguments needed for the
function call. The function should then be called. After calling
the function, the driver should display the function results.
Driver to test function computeSum( ):
int main( )
{
int n;
// Keep calling computeSum( ) and displaying the result.
do
{
cout << “Enter number of items or 0 to quit: ”;
cin >> n;
cout << “The sum is “ << computeSum(n) << endl;
} while (n != 0);
}
return (0);
// end driver
When you are sure that the function works properly, you can
substitute it for its stub in your program system. This process of
separately testing individual functions before inserting them in a
program system is called bottom-up testing. After replacing all
of its stubs with functions that have been independently
pretested, you should test the entire system. These tests are
called system integration tests.
30
Chapter 6: Modular Programming
Debugging Tips for Program Systems
Here are some suggestions for debugging a program system.
1.
Use comments to document each function parameter
and local variable as you write your code. Also describe
the purpose of the function.
2.
Create a trace of execution be displaying the function
name as you enter it.
3.
Trace or display the values of all input and input/output
parameters upon entry to a function. Check that these
values make sense.
4.
Trace or display the values of all function outputs after
returning from a function. Verify that these values are
correct by hand computation. Make sure that you
declare all input/output and output parameters as
reference parameters using the ‘&’ symbol.
5.
Make sure that the function stub assigns a value to each
output parameter when testing.
In-Class Exercise:
Write a driver function to test the computeAverage( ) function.
31
Chapter 6: Modular Programming
6.6 Recursive Functions
C++ allows a function to call itself. A function that calls itself
is a recursive function. A recursive function is often used in
place of iteration or looping. A recursive function calls itself
repeatedly, but with different argument value(s) for each call.
The key to using recursion successfully is to include a
conditional test to terminate the recursion. This condition is
called a stopping case and is similar to the conditional
expression used to exit from a loop. Without a stopping case,
the function will call itself forever.
You need to realize that each time the function is called the
system creates a new set of automatic variables for that function
on the stack. The size of the stack grows in relation to the
number of times you call the function. If you call the function
too many times (which will happen if fail to incorporate a stop),
the stack could grow so large that you run out of stack space.
This is called a stack overflow.
Form or template for a recursive function:
If the stopping case is reached
Return a value for the stopping case
Else
Return a value computed by calling the
function again with different arguments.
32
Chapter 6: Modular Programming
Here’s a simple example:
Program 6-8
# include <iostream>
using namespace std;
// Function prototype
void upAndDown(int);
int main()
{
upAndDown(1);
return (0);
}
void upAndDown(int n)
{
cout << “Level “ << n << endl;
if (n < 4)
upAndDown(n+1);
cout << “LEVEL “ << n << endl;
}
Program output:
Level 1
Level 2
Level 3
Level 4
LEVEL 4
LEVEL 3
LEVEL 2
LEVEL 1
33
// print #1
// print #2
Chapter 6: Modular Programming
Fundamentals
Let’s look at some basic points of recursion.
1.
Each level of recursion or function call has its own set of
variables. Each has its own distinct value.
2.
Each function call is balanced with a return. Once the
program flow reaches the stopping case or return at the
end of the last recursion level, control is passed back to
the previous recursion level. Control moves back level
by level until the first function or recursion level is
reached. This process is called unwinding the recursion.
3.
Statements in a recursive function that come before the
recursive call are executed in the same order that the
functions are called. They are executed as control is
passed forward.
4.
Statements in a recursive function that come after the
recursive call are executed in the opposite order from
which the functions are called. They are executed as
control is being passed backward.
5.
Although each level of recursion has its own set of
variables, the code itself is not duplicated. The code is a
sequence of instructions, and a function call is a
command to go to the beginning of that set of
instructions.
34
Chapter 6: Modular Programming
Tail Recursion
The simplest form of recursion is called tail recursion, or end
recursion, because the recursive call comes at the end of the
function before the return statement. This type of recursion acts
like a loop.
Recursive function for factorial:
// Returns: The product of 1 * 2 * 3 * … * n for n > 1;
//
otherwise 1.
int factorial(int n)
{
if (n <= 1)
return 1;
else
return (n * factorial(n – 1)); // Recursive call
}
Iterative function for factorial:
// Returns: The product of 1 * 2 * 3 * … * n for n > 1;
//
otherwise 1.
int factorial(int n)
{
int productSoFar = 1 ;
// output: accumulated product
for (int i = n; i > 1; i--)
productSoFar = productSoFar * i;
return (productSoFar);
}
35
Chapter 6: Modular Programming
The main( ) function for either factorial:
#include <iostream>
using namespace std;
int factorial(int);
// function prototype
int main()
{
int num;
cout << "This program calculates the factorial "
<< "for any integers\n"
<< "entered by the user. Please enter only "
<< "positive integers\n"
<< "under 16." << endl << endl;
do
{
cout << "\nEnter a positive integer (or 0 to quit): ";
cin >> num;
if (num < 0)
cout << "No negative numbers, please." << endl;
else if (num > 15)
cout << "Keep input under 16." << endl;
else
cout << "The factorial for " << num << " is: "
<< factorial(num)
<< endl;
} while (num != 0);
return (0);
}
36
Chapter 6: Modular Programming
In-Class Exercise:
1. Write a recursive function that, given an input value of n,
computes: n + (n – 1) + … + 2 + 1.
2. Given the following code, fill in the recursive function to
print the users input in reverse:
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;
void readInput(string&);
// prototype
void printBackward(string, int);
int main()
{
string inString;
readInput(inString);
// function call
cout << "\nYou entered: " << inString << endl;
return (0);
}
void readInput(string &input)
{
char ch;
cout << "Enter a line of input: ";
do
{
ch = getchar();
if (ch == '\n')
input += '\0';
else
input += ch;
} while (ch != '\n');
return;
}
void printBackward(string input, int n)
{
// Enter recursive code here
}
37
Download