The goal is to:
Learn about void functions
Learn how to return more than one values from a function
Learn to write a more complex code with multiple function calls
Before we begin this lab, please change your directory to cs1440 or 1440 (depending on which one you have), and in that directory, create the lab5 directory and change to that directory. You will do all your work in the lab5 directory. (% cd cs1440 ... then %mkdir lab5, .... then %cd lab5).
Part 1. Void Functions
We have seen and used functions that return a value. There are times, however, when it is convenient to create a function that carries out some activity
but does not produce a value. An example of such a function is one that prints instructions to the user. Remember the cost.C program in the textbook?
We used that program in Lab #5. The cost.C program didn't really provide much in the way of instructions for the user. We could improve it by adding
some cout lines that tell the user more about what the program does. But if we put those extra lines into the main function, we will clutter up main and
make it longer and more tedious to read. Instead, we will put the user instructions in a separate function named (what else?) "instructions". Look at the
program now and pay attention to how the instructions function is being called from the main function.
double total_cost(int number_par, double price_par);
//Computes the total cost, including 5% sales tax,
//on number_par items at a cost of price_par each.
//Tells the user what the program does.
int main( )
double price, bill;
cout << "Enter the number of items purchased: ";
cin >> number;
cout << "Enter the price per item $";
cin >> price;
bill = total_cost(number, price);
cout << number << " items at "
<< "$" << price << " each.\n"
<< "Final bill, including tax, is $" << bill
double total_cost(int number_par, double price_par)
const double TAX_RATE = 0.05; //5% sales tax
= price_par * number_par;
return (subtotal + subtotal*TAX_RATE);
cout << "\n\nBILL CALCULATOR!\n\n"
<< "This program will calculate the total cost, "
<< "including tax,\n"
<< "of a quantity of items being purchased. You "
<< "will be asked\n"
<< "for the number of items purchased and the cost "
<< "of each one.\n\n";
Copy the program into your lab5 sub directory and call it "cost.C". Compile and run it. Be sure you understand its behavior now.
Look at the display below. We have shown the prototype of the function
and the call to that function for each of the two functions in the above
prototype: double total_cost(int number_par,
call: bill = total_cost(number, price);
prototype: void instructions(void);
The total_cost function returns a value of type double. This will value will be "recieved" by the calling function with the same type. Thus, when it comes back to the calling function, we have to save the returned value in a variable of the same type. That's why we put the call on the right-hand-side of an assignment statement and assign the return value to the variable, bill. Also, total_cost has two parameters. The first one is an integer and the second one is a double. When we call the total_cost function, we must pass it two values, an integer and a double.
Now look at the prototype and the call for the instructions function.
The instructions function has a void return type (the word void tells C++
function returns no value), so it is not necessary to catch any return value. And since the function has no parameters, it is not necessary to send it any
values when we call it. Thus the call includes only the name of the function and an empty argument list. Note that the parentheses after the name of the
function are necessary. Also note that the word "void" is not used in the call. Instead, the parameter list is simply left blank. It is an error to put the word
"void" in the function call.
Don't let the difference between the names of the parameters in the
total_cost function and the names of the variables whose values are being
the function bother you. When C++ gets to the assignment statement, "bill = total_cost(number, price)", the first thing it does is look into memory and
get the values of number and price. It then sends those values to the total_cost function. The values are used to initialize the parameters of the
total_cost function. The total_cost function has no way of knowing what the variables in main are called, and main has no way of knowing what the
parameters of the total_cost function are called. The calling mechanism merely copies values from one place in memory to another. The names of those
places may be exactly the same or they may be different; it doesn't matter.
There is one other void function that we might find nice to have for our cost.C program. The formatting lines
You can move these lines to a void function so your main program is more readable.
Edit your program and move the lines into a void function named "format". Then just call the function from inside main by saying
Don't forget that you will need a prototype for the format function
above main and some comment lines that tell what the function does. Compile
run your program now. Try 3 items at $14.45 each. Did you get $45.5175? Then you forgot to call your new format function. You should get $45.52.
Part 2: Functions that "Return" More than One Value
The get_input function needed to obtain two values from the user and
give those values to the main function. In a sense, then, get_input "returns"
values. At least, it produces two outputs. This cannot be done with the return statement because the return statement returns exactly one value. If a
function must produce more than one output value, then we must use call-by-reference parameters (one for each output value.)
// This function is to illustrate how a function
can return two values
// This the declaration of the function that add
10 to i and 20 to j
void Process(int& i, int& j);
cout << "Enter two integer values, first i then j \n";
cin >> i >> j;
cout << "I added
10 to i, and 20 to j \n";
cout << "i is= " << i << " and j is= " << j << "\n";
void Process(int& i, int& j)
i = i +10;
j = j +20;
AS you can see in the above example, if we wouldn't use the & by the variables i and j, then i and j would not change after the function call. Using & we access the address of i and j and will change the values at their memory locations. Calling variables by their address is called call-by-reference.
Of course, we could write two functions instead of one to get input
from the user. We could write get_number and get_price, and have each of
return one value with a return statement. It is the choice of the programmer which kinds of functions to write for a given task. The goal of the
programmer should be to make the program work correctly and also be easy to read and understand.
Part 3: A Case Study
Suppose we have been asked to create a program that will allow a user
to create rectangles and triangles on the screen. The shapes will be made
of a character chosen by the user. The user may also choose the size of the rectangle or triangle by inputting the number of rows and columns for a
rectangle and the number of rows for a triangle. Here are some samples:
The first shape is a rectangle made of x's with 3 rows and 5 columns. The second shape is a triangle made of o's with 6 rows. All our triangles will be right triangles drawn so that each row after the first row is one character longer than the row just above it.
Your homework for this lab will be to create this program, but I am going to lead you through its creation.
Sometimes when you write a new function, you make use of a driver program
to test it. A driver is a small program written only to test a new function.
When you are working on a program that will contain many functions, you should test each function separately from the others. Once a function has
been tested, it can be used in a program that is testing a different function, but each function should be tested in a program in which it is the only
We are also going to make use of function stubs. We will say more about this idea shortly.
The first task to be done when writing a large program is to decide
on a design for that program. The most important part of designing a program
deciding what functions need to be written and what kind of function each will be.
We can describe a design most easily with a picture called a structure
chart. The structure chart contains a rectangle for each function labeled
name of the function. The rectangles are drawn in such a way that the chart shows which function calls which. If function X calls function Y, then the
rectangle for X will be above that for Y and there will be a line connecting X to Y. The following structure chart describes our new and improved
For each function we show the inputs to the function with a downward-pointing
arrow, and the outputs with an upward-pointing arrow. If there are
more than two outputs, as for the get_input function, we will use call-by-reference parameters for those outputs. Otherwise we will use the return
statement. The order in which functions are shown left to right is unimportant in a structure chart. The only information conveyed is "who calls who and
how". Make sure you understand why the structure chart for cost.C is drawn the way it is.
Design for draw.C
Here is a structure chart for the draw.C program we are going to write for homework.
In addition to the structure chart in our design, we need to say a few
words about what each function does. These explanations can later be made
of the comments written next to the prototypes of the functions. Here is a brief description of each function to be included in draw.C:
instructions: The instructions function will tell the user that the
drawing program will draw rectangles and triangles of different sizes on
the screen and
that the user may select the size and the character to be used for drawing. It should tell the user that he or she will be making selections from a menu.
menu: The menu function will display the following menu:
1. Draw rectangle.
2. Draw triangle.
It will then ask the user to select one of the choices. The function should verify that the choice is a 1, 2, or 3, and should then return that choice to main.
draw_rect: Given a number of rows, a number of columns, and a character
to use for drawing, this function draws a rectangle on the screen. It calls
the make_row function to produce each row of the rectangle.
draw_tri: Given a number of rows and a character to use for drawing,
this function draws a triangle on the screen. It calls the make_row function
produce each row of the triangle. Each row of the triangle after the first row is one character longer than the row above it.
make_row: Given a number, num, and a character, ch, this function prints num ch's in a row. It does not place a newline at the end of the row.
get_rows_cols: The get_rows_cols function is called when the user wants
to draw a rectangle. The function asks the user for the number of rows
the number of columns to be used in creating the rectangle, and "returns" those numbers to main. (Call-by-reference!)
get_rows: The get_rows function is called when the user wants to draw
a triangle. The function asks the user for the number of rows to be used
creating the triangle and returns that number to main.
get_drawchar: The get_drawchar function is called for any shape the
user wants to draw. The function asks the user what character should be
the drawing and returns that character to main.
Implementing the design
You should not change the design of the draw.C program. The design was
crafted to be a valuable learning experience for you. This is certainly
only way that the draw.C program could be written, but it is the way I want you to write it.
One hard part of the program is now done. We have decided how the work
to be done by the program should be divided up among all our functions.
Now we pick a function to write first and get started. Normally we begin by writing the main function, but this time let's begin by writing the make_row
The make_row function has two call-by-value parameters, an integer and
a character. Let's call the integer num and the character ch. The function
supposed to write ch on the screen num times. We will need a loop that runs num times to accomplish this task. Create a file called "driver.C" and
copy the following into it. The main function here is a driver for the make_row function.
void make_row (int num, char ch);
//Writes num ch's on the screen, all in a row.
int main (void)
cout << "\n\nDriver
to test make_row function.\n\n";
cout << "This program will repeatedly ask you for a "
<< "number and a character\n"
<< "and will send that number and character to "
<< "make_row. When you\n"
<< "are satisfied that make_row works properly, "
<< "enter 0 for the number.";
cout << "\n\nYour number (0 to quit): ";
cin >> num;
while (num > 0)
cout << "\nYour character: ";
cin >> ch;
cout << "\n\nYour number (0 to quit): ";
cin >> num;
A driver is a function designed to test another newly written function.
The main function above will not be used in the draw.C program. Its usefulness
temporary, only long enough to be sure that the make_row function is correct.
Now write the make_row function below main. Give it a loop that runs
num times, printing ch each time. Once you have written the function, compile
and test your program. You can't go forward until your make_row function is working properly.
Now let's write the main function for the draw.C program. Here is an
algorithm that describes what main must do. See if the algorithm makes
1.Print instructions for the user.
2.Print the menu and get the user's choice (1, 2, or 3).
3.While the user's choice is not 3
1.If the user's choice is 1 (draw a rectangle)
1.Get the number of rows and the number of columns to use for the rectangle.
2.Get the character to use in drawing the rectangle.
3.Draw the rectangle.
2.Else if the user's choice is 2 (draw a triangle)
1.Get the number of rows to use for the triangle.
2.Get the character to use in drawing the triangle.
3.Draw the triangle.
3.Print the menu again and get the user's next choice.
4.Thank the user for using the program.
After you think about the order in which we have listed the steps of
the algorithm, figure out which instructions of the algorithm go with which
The functions in our design are
You should now begin to see how the main function will be encoded in
C++. Step 1 of the algorithm will be replaced by a call to the instructions
function. Steps 2 and 3(c) will be replaced by calls to the menu function.
Step 3(a)(i) will be replaced by a call to get_rows_cols, step 3(b)(i)
will be replaced by a call to get_rows, and steps 3(a)(ii) and 3(b)(ii)
will be replaced by calls to get_drawchar. Finally, step 3(a)(iii) will
be replaced by a call to draw_rect and step 3(b)(iii) will be replaced
by a call to draw_tri. Notice that there is no call in main to the make_row
function we have already
written. That's because draw_rect and draw_tri are the callers of that function.
Create a file called draw.C. Begin with the #include line, then write all the function prototypes with comments for each one. You should be able to decide on the form of a prototype by looking at the structure chart and at the description of the function below the structure chart. If the function produces no output value, it is a void function. Otherwise, it's return type will be the return type of its output value, unless, of course, the function produces two output values, like get_rows_cols. Then it will be a void function and it will have two call-by-reference parameters. To decide on the parameter list for each function, look at the structure chart and see if the function has any inputs. If so, it will need a call-by-value parameter for each of its inputs. The only function that needs call-by-reference parameters is get_rows_cols.
After you have written all the prototypes, write the main function using the algorithm given above. You might find it useful to copy and paste the lgorithm into your program and then change each step into C++. Many of the steps turn into function calls. Go ahead and write the appropriate function calls. Don't neglect to declare any variables that you use in your main.
We are not going to write every function in final form right now, but we are going to write a stub for each function. A stub is a function that tells you its name, tells you the values of its call-by-value parameters, and returns some reasonable value(s) if it is supposed to. Like a driver, a stub's usefulness is temporary. As your program progresses toward completion, you turn each stub into a finished function, one at a time.
After your main, insert the following:
void draw_tri(int rows, char drawchar)
cout << "Draw_tri function called.\n";
cout << "Rows came in as " << rows
<< " and drawchar came in as " << drawchar << endl;
cout << "Get_rows function called.\n";
void get_rows_cols(int& rows, int& cols)
cout << "Get_rows_cols function called.\n";
rows = 5;
cols = 10;
cout << "Instructions function called.\n";
cout << "Menu function
cout << "What shall I return for a choice this time? ";
cin >> choice;
These are five of the stubs we need in the program. Be sure that the first line of each stub looks like the prototype you placed above main. The body of a stub should contain a cout statement saying that the function has been called. If the function has call-by-value parameters, the stub should contain cout's that say what the values received were. If the function is supposed to return a value, you should choose a reasonable value and have the stub return that value. The value 5 was selected for get_rows to return because 5 is a reasonable number of rows for a triangle to have (get_rows is called when the user wants to draw a triangle.)
Study the stubs you just placed in your program. Be sure you understand what each one is going to do when your main calls it.
You might wonder about the menu stub. It presented a little problem.
If we made 1 be the return value, then main would always call the draw_rect
function. If we made 2 be the return value, then only draw_tri would get called, and if we made 3 be the return value then the program would just quit.
So we will have the menu stub read a value from the user and return that value.
All you want to do right now is test to see if your main function works.
Write a stub for each of the other functions called by main and put them
underneath main. The order of the stubs is not critical. Whatever order you choose will probably be the order of the functions in the final program. It is
usually best to put them in alphabetical order so you can find them easily. Note that you do not need a stub for the make_row function. We will
incorporate that function into draw.C when we write the final versions of draw_rect and draw_tri.
After you have finished all the stubs, compile and run draw.C. It will
not, of course, draw any rectangles or triangles, but you should be able
to tell if the
right functions are getting called at the right times. To complete the program, you will turn each of the stubs into a finished function. Let's start with
This function does not receive any arguments. It simply asks the user
for a character and returns that character to main. Edit draw.C and find
for get_drawchar. You will now delete the cout that says that the function was called and you will replace it with a cout that asks the user to enter a
character. Declare a local character variable and read the user's character into that variable. Then return the value of that variable instead of the
character your stub was returning.
After you write get_drawchar, save your program and compile it. Run
the program. The only change in its behavior should be that it now lets
a character and it shows you that character from the draw_rect and draw_tri functions, instead of the one you were using in the stub.
Now let's work on draw_rect. Let's think about how we can use the make_row
function to draw a rectangle. Draw_rect has two integer parameters,
rows and cols, and we want it to draw a rectangle rows high and cols wide. It also has one character parameter, drawchar, and we want it to make
the rectangle out of that character. (Your names may be different.)
The make_row function has one integer parameter, num, and one character
parameter, ch. Clearly, when draw_rect calls make_row, it should pass
drawchar, but should it pass rows or cols? The answer is, it should pass cols, because that is the length of each row and make_row is going to make
How many times should draw_rect call make_row? The answer is, rows times.
So we need to put a while loop in draw_rect that runs rows times. That
means we need a local variable that will serve as a counter.
Delete the lines of your stub that are giving the name of the function
and printing out the values of its parameters. Declare your counter, then
put in your
while loop. Inside the body of the while loop you should call make_row and add one to your counter. There is one other thing that you must do, and
that is to print out a newline after each call to make_row. Remember that make_row does not put a newline at the end of the row.
It is now time to put make_row into draw.C along with a prototype for
it. I'll show you a handy feature of vile. First save draw.C. Then make
of driver.C using the following Unix command:
cp driver.C make_row.C
Now edit make_row.C and delete everything except the make_row function.
Save the file. Now run vile on draw.C and find the place in that file where
you want to put the make_row function. Your cursor should be on the line just above where you want make_row to be. Be sure you are in command
mode and issue the following command to vile.
The "r" in the vile command stands for "read". You should now have a
copy of make_row inside draw.C. Put your cursor on the first line of the
and type "yy". Then move your cursor up to the prototypes in draw.C and put the cursor on the line just above where you want the prototype for
make_row. Then type "p". Now go to the end of the line and add the semicolon.
OK, now you are ready to test your draw_rect function. Remember that
you still have a stub for get_rows_cols, so all of your rectangles will
size your get_rows_cols is producing. However, you should be able to draw rectangles out of whatever character you choose.
Let's build the get_rows_cols function next. This will be the only function
we need to write that must use call-by-reference parameters. We must use
call-by-reference since the function needs to produce two different values.
We are calling get_rows_cols from main and passing main's two variables,
rows and cols, to the function. We want the function to receive the variables
themselves, and not the values of the variables. So the prototype of the function is:
void get_rows_cols(int& rows, int& cols);
Right now our stub is assigning 5 to rows and 10 to cols. Change the
function so that it asks the user for a value for each of its parameters.
Be sure to
get rid of the cout statement saying that the function was called.
Now compile and run draw.C. You should be able to draw rectangles of any size you choose and out of any character you choose.
Right now is a good time to think about how you want to make use of
the screen as the program runs. There should be white space separating
shapes from things above and below them. All the questions that are asked for one shape should come in a cluster. The menu should be set off from
other things once you complete the menu function.
Your assignment is to finish the draw.C program. You will have to work on get_rows, draw_tri, instructions, and menu. Part of wrapping up the program should be the addition of a program header containing your name, your login name, the file name, the date, and a brief description of the program. Your variables should have comments after them stating their purpose. Your code should be written using proper indentation style. Each function prototype should be followed by a comment describing that function.
Your program must be submitted by midnight Tuesday, March 6.
Call your program lab5.C and submit using the submit command:
~rt/bin/submit1440_10? lab5 lab5.C
In the above command line replace ? with appropriate