Chapter VIII
Program Modularity
and Functions
Chapter VIII Topics
8.1 Introduction
8.2 Identifying Program Segments
8.3 User-created Function Syntax
8.4 Using Void Functions in a Program
8.5 Functions Prototypes
8.6 Program Development with Stubs
8.7 Using the Main Function Properly
8.8 Using Functions to Save Time
8.9 Controlling Program Output with OutputSelection
8.10 Using User-Created Include Files
8.11 Header Files and Implementation Files
8.1 Introduction
It is not sufficient to write a program that works. “Works” means that the program generates the desired output for some requested input. The manner in which a program is written is extremely important. Computer scientists have learned over the years that failure to pay attention to proper program development brings disaster when programs become large. The disaster is the unreasonable effort required to alter and update existing programs and the unnecessary time devoted in debugging a faulty program. Later in this book an entire chapter will be devoted to program development. You will need more computer science tools to appreciate the language and concepts that are discussed in a thorough treatment of proper program design. At this stage we can start to introduce - and practice - one very important aspect of desirable program design: program modularity.
Modularity is the absolute corner stone of all problem solving. It is everywhere around you, and I am not talking about computer science now. I mean every area of life involves modularity. Breaking everything down to manageable modules is a human trait to accomplish practically everything. We use modules when we create complex objects, when we accomplish large projects, and when we teach.
Listen to this person teaching a friend how to play the card game, “Hearts” . . . . .
Are you familiar with Bridge? No? How about Spades? No again. What card games do you know? I see... that many. Well, I know the proper starting point now. This is a deck of cards. There are 52 cards in this deck ........
You may think that the example above is silly. But it is not silly at all for somebody who has had zero exposure to card games. Accomplishing anything requires that the given task is reduced to a level that can be managed. Cleaning an entire house is a pretty formidable task. It is better to concentrate on just one room, and in the case of some rooms it is better to start with the closet. Whatever the situation, people are confronted with jobs that are too large to manage. We divide the job into smaller chunks and then proceed to tackle each smaller subtask. It can be argued that people who have difficulty handling complex tasks may lack the ability to stop staring at the whole job and start concentrating on smaller components.
Creating, designing, developing - whatever you wish to call it - programs is a classic example of a job that requires subdividing for all but the smallest programs. There are many considerations in the process of developing a complex program, but right now our focus will be on dividing a program into multiple, smaller modules.
The tool for creating modules will be the function. You have already used some functions, but all the previously introduced functions were available in some include library. In this chapter the focus is on user-created functions, and how the function is used for two very important purposes.
The first purpose is to divide a program into smaller modules that are easier to manage. The second purpose is to recognize that certain tasks are repeated frequently in a program. Such repetitive tasks can be turned into a function that is written once but used many times.
Read and reread this chapter many times. Adhering to principles in this chapter will make your program writing easier. Ignoring some of the good, sound advice that will be presented here can make your computer science course unnecessarily difficult. There is no chapter that will make your programming life simpler than this chapter. Did I already mention that? Do you think that I am redundant? No doubt, but it bothers me and most other computer science teachers to see students unnecessarily spin their wheels in helter skelter program design.
8.2 Identifying Program Segments
It is just terrific to split up a large program into smaller modules, but how do you decide what kind of modules to use. Where are the splits made? Is a program divided up into modules of 20 program statements per module? That seems logical at first glance, and it will be easy to decide where to end and start a new module. A second look at any practical program will convince you that modules cannot all be the same size.
Consider cleaning the house again. Would it not be strange to clean the house in sections of 400 square feet? I am sure you would clean the house according to the rooms, or perhaps doing the walls and the floors, or the windows and the walls and the ceilings. Whatever you use, it is likely to be some part of the house that is very easy to recognize and does not require taking out a measuring tape.
For starters let us take a look at program PROG0801.CPP and observe the program segments that have been identified. This program does not use modules in the manner that you will learn to use modules. However, the program is divided up with comments and spaces to identify separate segments.
|
// PROG0801.CPP // This program demonstrates dividing a program into segments // according to the purpose of each segment.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
void main() { // VARIABLE DEFINITIONS double PayRate; // hourly wage int HoursWorked; // hours worked per week double GrossPay; // hours worked times hourly wage double Deductions; // taxes and social security payments double NetPay; // take-home pay after deductions
// ENTER DATA SEGMENT clrscr(); cout << "ENTER YOUR HOURLY PAYRATE ===>> "; cin >> PayRate; cout << "ENTER YOUR WEEKLY HOURS ===>> "; cin >> HoursWorked;
//PROCESS DATA SEGMENT GrossPay = PayRate * HoursWorked; Deductions = GrossPay * 0.28; NetPay = GrossPay - Deductions;
// DISPLAY DATA SEGMENT cout << endl << endl; cout << setiosflags(ios::fixed); cout << setiosflags(ios::showpoint); cout << setprecision(2); cout << "GROSSPAY: " << GrossPay << endl; cout << "DEDUCTIONS: " << Deductions << endl; cout << "NETPAY: " << NetPay << endl;
getch(); }
|
|
PROG0801.CPP OUTPUT
ENTER YOUR HOURLY PAYRATE ===>> 7.75 ENTER YOUR WEEKLY HOURS ===>> 20
GROSSPAY: 155.00 DEDUCTIONS: 43.40 NETPAY: 111.60
|
Program example, PROG0801.CPP showed you an important lesson about program modularity. The segments were not grouped according to size, but according to a common purpose. Every segment focused on one task.
· The first segment contained all the variable definitions.
· The second segment contained the program user prompts and statements necessary to enter data from the keyboard.
· The third segment computed all the necessary values.
· And, the fourth segment displayed the results of all the data.
|
Divide and Conquer with Modules |
|
Divide a program into modules that focus on a singular task that is manageable. Regardless of size, continue to divide any program segment that is too complex until a manageable task is reached.
A popular computer science saying is: One task --- one module
Ideally one program module should print on one piece of paper.
If a module becomes too large, divide it into smaller modules.
|
There is a lot more to this story. Right now we have introduced the general approach used to subdivide a program. The program method used to achieve that subdivision in an organized and efficient manner is the next topic.
8.3 User-Created Function Syntax
Dividing a program up into segments that are separated by spaces and identified by comments is just lovely, but there is a far better way. C++ gives you the ability to create your very own functions. After all, C++ has functions, and why should you not have the same convenience?
You have already used such functions as clrscr, getch, cout, and cin. You used these functions with minimal fuss, and without knowing what really is done to accomplish some of these tasks. You used the function names in program statements in a proper manner and you achieved desired results.
Ironically, you have been creating functions since the beginning of school. Does the function below look familiar?
|
// MAIN FUNCTION EXAMPLE
void main() { clrscr(); cout << ”THIS STATEMENT IS IN THE MAIN FUNCTION” << endl; getch(); }
|
That is right. The main part of your program that contains all the executable program statements is in fact an example of a function. However, it is a special function with the word main. What we need is a more general approach. Whether it is main or ProcessData you will notice the same syntax.
Program PROG0802.CPP shows a simple program that uses three user-created functions besides the main function. The program performs nothing useful, but the program exists to examine the syntax required for a user-created function. Check and see what all three functions have in common.
|
// PROG0802.CPP // This program demonstrates the proper syntax for // user-created void functions.
#include <iostream.h> #include <conio.h>
void Module1() { clrscr(); cout << "This is Module1" << endl; }
void Module2() { cout << endl << endl; cout << "This is Module2" << endl; }
void Module3() { cout << endl << endl; cout << "This is Module3" << endl; getch(); }
void main() { Module1(); Module2(); Module3(); }
|
|
PROG0802.CPP OUTPUT
This is Module1
This is Module2
This is Module3
|
This program example shows two important components of a user-created function. What is the precise make-up - required components - and syntax of a function, and how is a function used in a program? Three functions are shown. Notice that each function has a name. The name is preceded by the reserved word void. You may hear this type of function called a “void function.” Later, you will learn that we can create different types of functions, which do not use the word void. However, right now all our functions will start with void, hence the name “void function.”
Every function also use parenthesis following the function identifier, exactly like the main function. The parenthesis is not odd to you. After all, you have seen clrscr() and getch() besides main(). After the function name comes the function “body” or the function “block,” identified by opening and closing { } braces
|
Function Components and Syntax |
|
Function Components:
void Example() // function heading { // start of function body or block cout << endl; cout << ”Hello There” << endl; } // end of function body or block
|
8.4 Using Void Functions in a Program
The program in the previous section was strictly designed to illustrate the user-created function syntax. We have little use for programs that say “Hi I am Module1. Oh how nice of you to visit, I am Module2. Finally, I am so pleased you could stay, I am Module3.” We will look at the earlier payroll program - the one divided up into commented segments - and change those same segments into void functions in program PROG0803.CPP. Do not be disturbed by the comments at the top of the program that state that this program does not compile.
|
// PROG0803.CPP // This program divides the earlier program into void function // modules. This program does not compile because the variables // are defined "locally" inside a function.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
void Variables() { double PayRate; // hourly wage int HoursWorked; // hours worked per week double GrossPay; // hours worked times hourly wage double Deductions; // taxes and social security payments double NetPay; // take-home pay after deductions }
void EnterData() { clrscr(); cout << "ENTER YOUR HOURLY PAYRATE ===>> "; cin >> PayRate; cout << "ENTER YOUR WEEKLY HOURS ===>> "; cin >> HoursWorked; }
void ProcessData() { GrossPay = PayRate * HoursWorked; Deductions = GrossPay * 0.28; NetPay = GrossPay - Deductions; }
void DisplayData() { cout << endl << endl; cout << setiosflags(ios::fixed); cout << setiosflags(ios::showpoint); cout << setprecision(2); cout << "GROSSPAY: " << GrossPay << endl; cout << "DEDUCTIONS: " << Deductions << endl; cout << "NETPAY: " << NetPay << endl; getch(); }
void main() { Variables(); EnterData(); ProcessData(); DisplayData(); } |
|
PROG0803.CPP OUTPUT
// THIS PROGRAM DOES NOT COMPILE
Compiling PROG0803.CPP: Error PROG0803.CPP 27: Undefined symbol ’PayRate’ Error PROG0803.CPP 29: Undefined symbol ’HoursWorked’
|
You are probably surprised by the error message that the program does not compile. Everything looks in order. Each commented segment from the previous program has been neatly tucked inside a void function with a proper heading and function body. The main function calls each one of the new void functions in proper sequence. Life is good, so what is the problem? The problem is that all the variables have been placed into one function. This does seem to fit the spirit of one task--one module since the task of function Variables is to define all the variables. Every intention is good but we run into a little problem called Local Variables and Global Variables.
You would not have known it but the variable definitions of your “pre-function” programs were always inside the main function body. This meant that these variables were local to function main. This means that the variables defined in function main could only be used in function main. Now this causes little concern and conversation when all you have is the main function. But what if the picture has changed and we have multiple functions? The result of creating the Variables function is that all the variables are now local to function Variables and cannot be accessed anywhere else.
|
Local and Global Variables |
|
A local variable is defined inside a function and can only be accessed inside that function.
A global variable is defined outside all the functions and can be used anywhere in the program after the variable definition.
|
The local and global definition may not have made much sense to you. Look at program PROG0804.CPP and notice that all the variables are now defined at the top of the program before any of the functions. Also note that the variables are not inside the body of any function.
|
// PROG0804.CPP // This program divides the earlier program into // void function modules and shows the use of global variables.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
// GLOBAL VARIABLES
double PayRate; // hourly wage int HoursWorked; // hours worked per week double GrossPay; // hours worked times hourly wage double Deductions; // taxes and social security payments double NetPay; // take-home pay after deductions
void EnterData() { clrscr(); cout << "ENTER YOUR HOURLY PAYRATE ===>> "; cin >> PayRate; cout << "ENTER YOUR WEEKLY HOURS ===>> "; cin >> HoursWorked; }
void ProcessData() { GrossPay = PayRate * HoursWorked; Deductions = GrossPay * 0.28; NetPay = GrossPay - Deductions; }
void DisplayData() { cout << endl << endl; cout << setiosflags(ios::fixed); cout << setiosflags(ios::showpoint); cout << setprecision(2); cout << "GROSSPAY: " << GrossPay << endl; cout << "DEDUCTIONS: " << Deductions << endl; cout << "NETPAY: " << NetPay << endl; getch(); }
void main() { EnterData(); ProcessData(); DisplayData(); }
|
|
PROG0804.CPP OUTPUT
ENTER YOUR HOURLY PAYRATE ===>> 12.27 ENTER YOUR WEEKLY HOURS ===>> 30.25
GROSSPAY: 368.10 DEDUCTIONS: 103.07 NETPAY: 265.03
|
You may still be confused. Using global variables with this program seems to make everything work just fine. So why even bother with local variables? They only seem to cause problems. That is an excellent question and with time and exposure you will truly understand the nature of where variables belong. Right now you need to realize that there is a need for both local and global variables. Program PROG0805.CPP demonstrates the use of both global and local variables in one program. This program enters two numbers, displays them, swaps the numbers, and then displays them again.
|
// PROG0805.CPP // This program demonstrates the difference between // local and global variables.
#include <iostream.h> #include <conio.h>
// GLOBAL VARIABLES
int Number1, Number2;
void EnterData() { clrscr(); cout << "ENTER NUMBER 1 ===>> "; cin >> Number1; cout << "ENTER NUMBER 2 ===>> "; cin >> Number2; }
void SwapData() { int Temp; // LOCAL VARIABLE Temp = Number1; Number1 = Number2; Number2 = Temp; }
void DisplayData() { cout << endl << endl; cout << "Number 1: " << Number1 << endl; cout << "Number 2: " << Number2 << endl; }
void main() { EnterData(); DisplayData(); SwapData(); DisplayData(); getch(); }
|
|
PROG0805.CPP OUTPUT
ENTER NUMBER 1 ===>> 13 ENTER NUMBER 2 ===>> 31
Number 1: 13 Number 2: 31
Number 1: 31 Number 2: 13
|
There still may be some confusion. You see examples of local variables and global variables. It appears that global variables work in all situations, and local variables cause compile errors in some situations. So when do you use global variables, and when do you use local variables?
|
Using Global and Local Variables |
|
Use a global variable when the variable needs to be used in more than one function.
Use a local variable when the variable only needs to be used in one function.
|
|
|
8.5 Function Prototypes
Every function call that you have witnessed in this chapter has been a program statement in the main function. This is not a requirement. It is perfectly correct, and often desirable, to call functions from some other function that is not the main function. Program PROG0806.CPP shows a program that does precisely that type of function calling. This program is also a good example of learning to trace the program execution when multiple functions are called.
|
// PROG0806.CPP // This program demonstrates that functions can call each other. // It is also shows how to trace through a program // execution sequence.
#include <iostream.h> #include <conio.h>
void Module1() { cout << endl << endl; cout << "This is Module1" << endl; }
void Module2() { cout << endl << endl; cout << "This is Module2" << endl; Module1(); }
void Module3() { cout << endl << endl; cout << "This is Module3" << endl; Module2(); }
void main() { clrscr(); Module1(); Module2(); Module3(); getch(); }
|
Do yourself a favor. Do not turn the page and look at the program execution output. Right now look at this program, trace through its logic, and see if you can determine the correct execution sequence. The ability to trace through a computer and “play” computer is a very powerful debugging technique.
|
PROG0806.CPP OUTPUT
This is Module1
This is Module2
This is Module1
This is Module3
This is Module2
This is Module1
|
Did your program execution match the output shown above? Hopefully it did, and if you did not get the same output, trace carefully through the sequence of function calls again.
You have seen that user-created functions can be called from the main function, and they can also be called from any other function. It is easy to get relaxed here and assume that the story is finished. Be careful, there is more to this function calling business. Check out program PROG0807.CPP. It looks very similar to the previous program, but check the program output. There certainly is a major difference . . . like the program does not compile!
|
// PROG0807.CPP // This program demonstrates that functions can only be called // by other functions if a proper calling sequence is used.
#include <iostream.h> #include <conio.h>
void Module1() { cout << endl << endl; cout << "This is Module1" << endl; Module2(); }
void Module2() { cout << endl << endl; cout << "This is Module2" << endl; Module3(); }
void Module3() { cout << endl << endl; cout << "This is Module3" << endl; }
void main() { clrscr(); Module1(); getch(); }
|
|
PROG0807.CPP OUTPUT
// THIS PROGRAM DOES NOT COMPILE
Compiling PROG0807.CPP Error PROG0807.CPP 14: Function ’Module2’ should have a prototype |
You are pleased to learn that function ’Module2’ should have a prototype. Especially, since the only thing you know about a prototype is that the name appeared in the title of this section.
We have committed a rather formidable error in program PROG0807.CPP. We tried to call a function before the compiler has a clue that such a function exists. Inside function Module1 there is a function call for Module2. Now consider that the compiler checks if an identifier is a reserved C++ word, if the identifier is a C++ library function, or if the identifier is user-created. User-created identifier means that the compiler has some statement like a variable definition or a function heading that has given meaning to an identifier.
In other words, Module2 is as unknown as can be when the function call to Module2 is made inside function Module1. The previous program worked nicely because I took care to call the functions in the correct order. If a program does not have too many functions, keeping track of the function sequence is not so bad. With a large program and many, many functions, this can be very complicated. There is a better system by making sure to use function prototypes.
A function prototype is a function heading, by itself, with a semicolon. Program PROG0808.CPP uses the exact same execution sequence as PROG0807.CPP, but now the program has prototypes for each one of the functions. A close inspection of the program shows that more has changed than just the addition of some prototypes. The completed functions are now placed below the main function. Keep in mind that this is an important convention, but it is not a requirement.
The convention makes sense if you consider that it places the main function near the top of the program source code. Program execution starts in the main function and placement at the top of the program makes a program more readable.
|
// PROG0808.CPP // This program demonstrates that functions can call each other // out of order by using prototypes
#include <iostream.h> #include <conio.h>
// FUNCTION PROTOTYPES
void Module1(); void Module2(); void Module3();
void main() { clrscr(); Module1(); getch(); }
// FUNCTION IMPLEMENTATIONS
void Module1() { cout << endl << endl; cout << "This is Module1" << endl; Module2(); }
void Module2() { cout << endl << endl; cout << "This is Module2" << endl; Module3(); }
void Module3() { cout << endl << endl; cout << "This is Module3" << endl; }
|
|
PROG0808.CPP OUTPUT
This is Module1
This is Module2
This is Module3
|
Prototypes tell a compiler to relax and not get excited. A list of identifiers is presented to the compiler, which are the prototypes. This list implies that there is more to follow. Now when the compiler encounters Module2 before details about Module2 are given, no problem. After all, the prototypes let the compiler know that this identifier is correct and more information will follow later.
|
Prototypes Notes |
|
Prototypes allow functions to be called without any concern about the order that the functions have been defined.
Prototypes keep the main function at the beginning of the program, since the complete functions (implementations) can now be placed below the main function.
Remember that a prototype is a function heading with a semi-colon at the end.
By convention function prototypes are placed before the main function, and function implementations are placed below the main function body.
|
8.6 Program Development with Stubs
We have now arrived at a very critical topic in computer science. This topic of stubs is embraced by many students and they soon see the benefits. On the other hand, I have seen students who simply refuse to use this wonderful tool. The tool you are about to learn makes program writing quicker because you will have so little trouble identifying error locations.
There is a real irony in this topic. Actually it is not an irony, it is a paradox. Everything you see will appear as if you are taking longer to write a program. Many students reject anything that prolongs the program writing process. But this is only an illusion. It only appears like you take longer, and in reality you save a lot of time.
If you want an extremely useful tool to speed up program writing, read on. If you prefer to do your own thing and not follow some dumb-looking suggestion, skip this section. You do not need to know this part to write your programs. This stuff is only important if you want to write your programs quicker. It is not required to write quick programs . . . only to write complete and correct programs.
Before we get started I need to remove any potential curiosity and curb your excitement. Stubs do not look very exciting. Now they accomplish amazing things, but they simply are not very impressive. What is a stub? It is a function without any program statements.
|
Stub Definition |
|
A stub is a function without any program statements.
Stub Example:
void EnterData() { }
|
We will now look at the development of a program from the very beginning to the final end using stubs. Every step along the way will be shown with a program that demonstrates the latest program writing stage.
Using Stubs, Step 1
This is the first stage in the program development sequence with stubs. Make sure to read the comments at the start of each program. The comments are brief but they do assist in explaining the purpose of each program stage.
|
// PROG0809.CPP // Using Stubs for program development // Step 1, starts with the main function and include statements. // This step does not compile yet.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
void main() { EnterData(); ProcessData(); DisplayData(); }
|
|
PROG0809.CPP OUTPUT
There is no output. This program does not compile.
|
Step 1 starts by writing the main function. You can also write the include statements for the library function, if you know which ones are needed. This first step does not compile because none of the function names used in the main function have been declared before using them. The purpose of the first step is to concentrate on the main module divisions of the program. Give each module a logical name that indicates the purpose of the function and write the sequence of function calls in the main program function.
Using Stubs, Step 2
In step 2, write prototypes for each one of the functions called in the main function body. This step is somewhat unusual. Program PROG0810.CPP does compile, if you only select compile. However, the program will not “make” an executable file, which is a combination of compiling and linking. Look at this program stage. There are the necessary prototypes now. This satisfies the compiler, but without writing the implementations of the prototypes, there is nothing to link into a final code file.
|
// PROG0810.CPP // Using Stubs for Program Development // Step 2, writing prototypes // This program compiles, but it will not link.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
void EnterData(); void ProcessData(); void DisplayData();
void main() { EnterData(); ProcessData(); DisplayData(); }
|
|
PROG0810.CPP OUTPUT
There is no output yet. This program compiles, but it does not link.
|
Using Stubs, Step 3
Step 3 is the first stage that makes (compiles and links) an executable code file. The program output is totally unimpressive. You see nothing, but technically speaking, the program does execute. In this case, three functions are called. Each function is a stub. These empty function stubs allow a very minimal program to execute. This becomes significant when you start to test different components of the program. This is the first stage where actual stubs are used.
// PROG0811.CPP // Using Stubs for Program Development // Step 3, writing stubs for each prototype // This step compiles and links.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
void EnterData(); void ProcessData(); void DisplayData();
void main() { EnterData(); ProcessData(); DisplayData(); }
void EnterData() { }
void ProcessData() { }
void DisplayData() { }
|
|
PROG0811.CPP OUTPUT
This program has no noticeable output. The program compiles, and it links, but the stub functions are completely empty.
|
Step 3 can be done very quickly with block copying. Make a block of all the function prototypes. Copy them below the main function. Remove the semicolon from each function heading, add a set of { }, and you have a stub. This block copying approach is not only a time saver, it also increases accuracy. It is easy to make typo errors or to forget the precise function name. With the block copy method you are guaranteed to have the identical names for the prototypes and the function implementations. Just remember to remove the semicolons.
Using Stubs, Step 4
It is not sufficient to know that a program compiles and links properly. A totally illogical program that executes all the functions backwards will compile properly. The compiler is not designed to check program logic. The next step after checking if a minimal stub program compiles, is to insure that the program executes in the proper sequence. This stage is done by using “glorified stubs.” This type of stub is just one notch above a function heading with an empty body. You take the empty stub and add a couple program lines to skip some lines and indicate the name of the function stub.
|
// PROG0812.CPP // Using Stubs for Program Development // Step 4, creates "glorified stubs" which helps to show // the global execution sequence of a program.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
void EnterData(); void ProcessData(); void DisplayData();
void main() { clrscr(); EnterData(); ProcessData(); DisplayData(); getch(); }
void EnterData() { cout << endl << endl; cout << "ENTER DATA FUNCTION" << endl; }
void ProcessData() { cout << endl << endl; cout << "PROCESS DATA FUNCTION" << endl; }
void DisplayData() { cout << endl << endl; cout << "DISPLAY DATA FUNCTION" << endl; } |
|
PROG0812.CPP OUTPUT
ENTER DATA FUNCTION
PROCESS DATA FUNCTION
DISPLAY DATA FUNCTION
|
Yes, I know the output of the program is rather skimpy and lacks practical value to you. Please keep in mind that teachers are always faced with a dilemma. When teachers introduce a new concept, they want to focus on the concept and keep the examples short and simple. This approach makes it easier to learn new concepts and new syntax, but it also lacks reality. Students look at a small example and ask why this new concept is needed. In the current example, with a few functions, it is quite easy to follow the program logic. Keep in mind that this method of checking the program execution sequence - called global flow - is meant for large programs. Large prograams with hundreds and thousands of lines of code can easily become an intricate maze. The use of these glorified stubs helps to identify the path that the program execution takes.
Using Stubs, Step 5
With step 5 the reason for stubs will start to become more clear. In the last step you created a complete program. Complete in the sense that the program compiled, linked and it did help to check global flow. Now, you can start seeing the most important reason for using stubs. In this step the first function, EnterData, is completed.
At first this may seem rather insignificant, but you must realize that the last step presented a completed program that compiled. Starting with this step you will strictly focus on the completion of an individual function. This means that any problem you encounter, starting with compile error, is caused by changes in the current function. You see, one of the most difficult problems facing you in writing a program is isolating the location of an error. A student who writes an entire program from scratch, and waits with compiling and checking until the program is finished, will not have a clue where to start when the program has errors. Notice I did not say if, I stated when. The nature of errors, especially compile errors, is such that the compiler gets easily confused. The result is that error messages are indicated in program locations that are not even close to the cause of the error.
|
// PROG0813.CPP // Step 5 completes the EnterData function // This step also define global variables for EnterData.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
double PayRate; // amount paid per hour double HoursWorked; // number of hours worked per week
void EnterData(); void ProcessData(); void DisplayData();
void main() { clrscr(); EnterData(); ProcessData(); DisplayData(); getch(); }
void EnterData() { cout << endl << endl; cout << "ENTER DATA FUNCTION" << endl; cout << endl; cout << "ENTER YOUR HOURLY PAYRATE ===>> "; cin >> PayRate; cout << "ENTER YOUR WEEKLY HOURS ===>> "; cin >> HoursWorked; }
void ProcessData() { cout << endl << endl; cout << "PROCESS DATA FUNCTION" << endl; }
void DisplayData() { cout << endl << endl; cout << "DISPLAY DATA FUNCTION" << endl; }
|
|
PROG0813.CPP OUTPUT
ENTER DATA FUNCTION
ENTER YOUR HOURLY PAYRATE ===>> 7.75 ENTER YOUR WEEKLY HOURS ===>> 25
PROCESS DATA FUNCTION
DISPLAY DATA FUNCTION
|
Step 5 does not process any data yet, besides data input, but it is a good habit to run the program anyway. Enter some data and watch the result. You can at least check if the EnterData function prompts and behaves correctly.
Using Stubs, Step 6 & 7
The final stages in this stub business is to complete the remaining functions. Avoid the temptation to rush through and complete several functions at once. You need that isolation certainty. In step6 the ProcessData function is completed. You try to compile the program, there is some problem, and the error indicator makes no sense at all. Yet you know that the problem must be caused by something you have done in the ProcessData function. This certainty is only available when you truly use the “stub method” of completing one function at a time and then checking the program.
|
// PROG0814.CPP // Step 6 completes the ProcessData function. // This step also defines additional global variables // for ProcessData.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
double PayRate; // amount paid per hour double HoursWorked; // number of hours worked per week double GrossPay; // total amount earned in one week double Deductions; // federal tax and social security double NetPay; // weekly take-home pay after deductions
void EnterData(); void ProcessData(); void DisplayData();
void main() { clrscr(); EnterData(); ProcessData(); DisplayData(); getch(); }
void EnterData() { cout << endl << endl; cout << "ENTER DATA FUNCTION" << endl; cout << endl; cout << "ENTER YOUR HOURLY PAYRATE ===>> "; cin >> PayRate; cout << "ENTER YOUR WEEKLY HOURS ===>> "; cin >> HoursWorked; }
void ProcessData() { cout << endl << endl; cout << "PROCESS DATA FUNCTION" << endl; GrossPay = PayRate * HoursWorked; Deductions = GrossPay * 0.28; NetPay = GrossPay - Deductions; }
void DisplayData() { cout << endl << endl; cout << "DISPLAY DATA FUNCTION" << endl; }
|
|
PROG0814.CPP OUTPUT
ENTER DATA FUNCTION
ENTER YOUR HOURLY PAYRATE ===>> 7.75 ENTER YOUR WEEKLY HOURS ===>> 25
PROCESS DATA FUNCTION
DISPLAY DATA FUNCTION
|
|
// PROG0815.CPP // Step 7 completes the DisplayData function.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
double PayRate; // amount paid per hour double HoursWorked; // number of hours worked per week double GrossPay; // total amount earned in one week double Deductions; // federal tax and social security double NetPay; // weekly take-home pay after deductions
void EnterData(); void ProcessData(); void DisplayData();
void main() { clrscr(); EnterData(); ProcessData(); DisplayData(); getch(); } void EnterData() { cout << endl << endl; cout << "ENTER DATA FUNCTION" << endl; cout << endl; cout << "ENTER YOUR HOURLY PAYRATE ===>> "; cin >> PayRate; cout << "ENTER YOUR WEEKLY HOURS ===>> "; cin >> HoursWorked; }
void ProcessData() { cout << endl << endl; cout << "PROCESS DATA FUNCTION" << endl; GrossPay = PayRate * HoursWorked; Deductions = GrossPay * 0.28; NetPay = GrossPay - Deductions; }
void DisplayData() { cout << endl << endl; cout << "DISPLAY DATA FUNCTION" << endl; cout << endl; cout << setiosflags(ios::fixed); cout << setiosflags(ios::showpoint); cout << setprecision(2); cout << "GROSSPAY: " << GrossPay << endl; cout << "DEDUCTIONS: " << Deductions << endl; cout << "NETPAY: " << NetPay << endl; }
|
|
PROG0815.CPP OUTPUT
ENTER DATA FUNCTION
ENTER YOUR HOURLY PAYRATE ===>> 7.75 ENTER YOUR WEEKLY HOURS ===>> 25
PROCESS DATA FUNCTION
DISPLAY DATA FUNCTION
GROSSPAY: 193.75 DEDUCTIONS: 54.25 NETPAY: 139.50
|
Using the stub method is something that you need to do for yourself. It works. It really, really works, and it makes your life in the computer lab so much simpler. Lots of teachers are kind and help students regardless of their program writing approach. I am not so kind. I will help students who have difficulty, but students should not expect help if they cannot identify the function that is causing problems. Students are often perplexed when I say, “which function causes the problem?” Often they respond with a statement like, “if I knew where the problem was, I would not be asking you.” This is not true. When you write a program you do know where the problem is located. You probably do not know what causes the problem and how to fix the problem.
|
|
|
|
(stop here)
8.7 Using the main Function Properly
In the earlier chapters all the program examples placed every program statement in the main function. Large programs automatically created large main functions. In this chapter you have been introduced to modular programming. Now the main function is no longer the dumping ground for all the program statements. So what is the purpose of the main function in the world of modular programming?
This is an easy question with a short uncomplicated answer. The main function consists of function calls. It was not stressed that strongly before, but you may have noticed in the stub case study that only function calls were placed in the main function. The next program, PROG0816.CPP, demonstrates the technique of combining modular programming with prototypes and function calls in the main function. The result is that you get a clean, readable program where the main modules and global flow is shown at the top of the program.
|
// PROG0816.CPP // This program demonstrates modular programming with only // function calls in the program's main function body.
#include <iostream.h> #include <conio.h> #include <iomanip.h>
int Nr1,Nr2,Nr3; // three numbers to be averaged float Mean; // average of the three numbers
void Execution(); void EnterData(); void ComputeMean(); void DisplayData(); void Terminate();
void main() { Execution(); EnterData(); ComputeMean(); DisplayData(); Terminate(); }
void Execution() { clrscr(); cout << "----------------------------------------------------" << endl; cout << "=============== EXECUTION BEGINS ===============" << endl; cout << "----------------------------------------------------" << endl; }
void EnterData() { cout << endl << endl; cout << "ENTER THREE INTEGERS ===>> "; cin >> Nr1 >> Nr2 >> Nr3; }
void ComputeMean() { Mean = (float) (Nr1 + Nr2 + Nr3) / 3; // without (float) you will get integer division }
void DisplayData() { cout << endl << endl; cout << setprecision(4) << "MEAN: " << Mean << endl; }
void Terminate() { cout << endl << endl; cout << "----------------------------------------------------" << endl; cout << "============= EXECUTION TERMINATED =============" << endl; cout << "----------------------------------------------------" << endl; getch(); }
|
|
Modular Programming and the main Function |
|
The main program function needs to consist of a sequence of function calls, which represent the major program modules.
Function prototypes should be used and placed before the main function.
|
8.8 Using Functions to Save Time
The main thrust of this chapter is on program modularity. Break a large program into modules, and break large modules up into smaller modules. The C++ tool to assist you with program modularity is the trusty function. There is a closely related use of the function that certainly involves program modularity, but it is different enough to require a separate explanation section in this chapter.
You see, all the program examples in this chapter, have used functions for a certain singular task in the program. Essentially, the program was carved up into logical modules that performed a certain task, and each task became a function. There are other tasks in a program that are not sequential. Such tasks show up all over the program and they are repeated again and again. Picky teachers like myself and many other computer science teachers want the same number of spaces displayed between each program module. At the same time, program size will rapidly increase such that the program output does not fit on the screen. You will not be able to view the output unless you freeze each module’s output. What are we talking about? We have just mentioned two frequently used tasks. Specifically, skipping lines and freezing program output. Such tasks are excellent examples of another reason for creating user-defined functions.
Program PROG0817.CPP shows the generic type of program with the three input - process - output modules. However, inn this case functions Skip4 and Continue are created to make the programming job simpler. Basically, you create a function once, and then you can use it many times.
|
// PROG0817.CPP // This program demonstrate the use of a frequently used function.
#include <iostream.h> #include <conio.h>
void Skip4(); void Continue(); void EnterData(); void ProcessData(); void DisplayData();
void main() { clrscr(); EnterData(); ProcessData(); DisplayData(); }
void Skip4() { cout << endl << endl << endl << endl; }
void Continue() { cout << endl << endl; cout << "Press <Enter> to Continue"; getch(); }
void EnterData() { Skip4(); cout << "ENTER DATA FUNCTION" << endl; Continue(); }
void ProcessData() { Skip4(); cout << "PROCESS DATA FUNCTION" << endl; Continue(); }
void DisplayData() { Skip4(); cout << "DISPLAY DATA FUNCTION" << endl; Continue(); }
|
|
PROG0817.CPP OUTPUT
ENTER DATA FUNCTION
Press <Enter> to Continue
PROCESS DATA FUNCTION
Press <Enter> to Continue
DISPLAY DATA FUNCTION
Press <Enter> to Continue
|
It is too early in your computer science career to appreciate the value of creating functions for frequent tasks. I will assure you that it will not be long before you will develop a growing bag of function tricks that will make your program development simpler.
Always remember that computers are supposed to make the job of people simpler. Writing programs falls in that same category. People, like Grace Hopper, showed us that the computer can be used to make programming simpler. She helped to develop translators that allowed programming in a language much closer to human language. You are not expected to write program translators, but you are expected to take advantage of tools that have been created for you, and tools that you create for yourself. This also means that you will benefit from writing functions that are easy to understand and clearly commented. You will frequently in the future wish to copy program modules that you wrote earlier. Never waste time by re-inventing the wheel.
8.9 Controlling Program Output
with the OutputSelection Function
Printing program executions has not been that pleasant. You have probably been shown different techniques that all had a variety of problems. Now that you have been introduced to functions, we can show you a neat method to control the program output. Would it not be nice if the program asked if you want to direct output to the monitor or the printer? It certainly would, and in this section you will learn how to do this.
Now you must realize something. You will not really understand how this process actually works. A variety of programming techniques will be used that actually are introduced many chapters in the future. Why then use such techniques now? For starters, we really do not want to have the program output nuisance to the printer for much longer. For a second reason, it is nice to demonstrate that functions can be used effectively without actually understanding how the function performs its job.
Only a brief explanation will be given here. Your primary concern is to learn how to use the special OutputSelection function. The notion of using something without complete understanding is a fundamental tool in computer science called Information Hiding. We will mention this concept frequently in future chapters.
There exists a stream of information that is directed to the monitor with cout. You have been introduced to certain special features like setprecision and setw, but such features added control for monitor output only. At least so it appeared in earlier program examples. It is possible to create a special variable . . . a variable unlike any of type char, int, double or apstring. This special variable is of type ofstream (output file stream) and such a variable will behave in the same manner as cout. It also turns out that we have the ability to direct the output of this special output file stream variable to a location of our choice. This can be the monitor, the printer or some other device.
Now we have a special function, appropriately called OutputSelection, that gives the program user the option to select Monitor or Printer output. Take a look at program PROG0818.CPP, and check out all its unusual program statements.
You do not need to look far for unusual statements. The main function has some weird PO statements that behave like a cout function. There is char(12) and a new-looking close function The OutputSelection function that follows is plenty odd looking as well. You see four new, and unknown, C++ keywords in function OutputSelection: switch, case, open and default.
|
// PROG0818.CPP // This program demonstrates redirecting program output // to the printer with an OutputSelection function.
#include <iostream.h> #include <fstream.h> // required for file handling like PO #include <conio.h>
ofstream PO;
void OutputSelection();
void main() { clrscr(); OutputSelection(); PO << endl << endl; PO << "THE QUICK BROWN "; PO << "FOX JUMPS OVER" << endl; PO << "THE LAZY DOG" << endl; PO << endl; PO << "ON TUESDAYS ONLY" << endl; PO << (char) 12; // generates a formfeed PO.close(); getch(); }
void OutputSelection() { char Choice; cout << "WHERE DO YOU WISH TO DIRECT PROGRAM OUTPUT?" << endl; cout << endl; cout << " [A] Monitor" << endl; cout << " [B] Printer" << endl; cout << endl; cout << "PLEASE ENTER YOUR SELECTION ===>> "; cin >> Choice; switch(Choice) { case 'A' : case 'a' : PO.open("CON"); break; case 'B' : case 'b' : PO.open("PRN"); break; default : cout << "You must enter A or B" << endl; } } |
|
PROG0818.CPP OUTPUT
WHERE DO YOU WISH TO DIRECT PROGRAM OUTPUT?
[A] Monitor [B] Printer
PLEASE ENTER YOUR SELECTION ===>> A
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
ON TUESDAYS ONLY |
The program output that is shown, is a copy of what appears on the monitor. You will find that it will print an identical output to the printer. Do keep in mind that this is a generic technique, and certain lab setups, with special network arrangements, may require marching to a slightly altered drumbeat. It is very important that you precisely use the steps, which are shown on the next page. The first requirement in using strange code is to obey the user instructions.
|
Steps in Using the OutputSelection Function |
|
1. Include the file stream function library with #include <fstream.h>
2. Define an output file stream variable like ofstream PO; // Program Output variable
3. Copy the OutputSelection function exactly as it is shown in this chapter. Make no changes, unless specifically directed to do so by your teacher.
4. Make sure that OutputSelection is called in the main function before any output statement is used, or any function is called that uses an output statement.
5. Use the output file stream variable (PO in this case) in place of cout for every statement that you wish to control. Do not use the output variable for any statement that must always go to the monitor.
6. Conclude the program with a function call like PO.close(); to properly close the output file variable. |
Output Echoing to the Monitor
Everything seems to be going smoothly. Smoothly, that is until you try your nifty new OutputSelection function with some type of keyboard input statement. Suddenly you realize a little shortcoming. The lovely prompt that indicates what needs to be entered from the keyboard is now going to the printer. You are just staring at a blank screen. Properly using the OutputSelection function requires that you either have total recall of the program input requirements or that you echo any prompts statements to the monitor. Essentially, you generate output that will go both to the printer and monitor. Suddenly you seem confused. Isn’t the whole point of this high-tech function to let people select monitor or printer. If the output goes to both places, why waste time selecting output?
That is an excellent point, and we do wish to select the majority of our output to go to either the monitor or the printer. Right now we are strictly talking about the special situation of keyboard input, and the prompt that precedes it. Besides, something has to be done about keyboard input anyway, because input is input and cannot be controlled by program output. Yet another reason for this echo business has popped up. Program PROG0819.CPP shows a solution to this sticky problem.
|
// PROG0819.CPP // This program demonstrates echoing information to the monitor // that would normally only show up on the printer.
#include <iostream.h> #include <fstream.h> // required for file handling like PO #include <conio.h>
ofstream PO; int Number; void OutputSelection(); void EnterData(); void DisplayData();
void main() { OutputSelection(); EnterData(); DisplayData(); }
void OutputSelection() { char Choice; clrscr(); cout << "WHERE DO YOU WISH TO DIRECT PROGRAM OUTPUT?" << endl; cout << endl; cout << " [A] Monitor" << endl; cout << " [B] Printer" << endl; cout << endl; cout << "PLEASE ENTER YOUR SELECTION ===>> "; cin >> Choice; switch(Choice) { case 'A' : case 'a' : PO.open("CON"); break; case 'B' : case 'b' : PO.open("PRN"); break; default : cout << "You must enter A or B" << endl; } }
void EnterData() { PO << endl << endl; cout << "Enter a number ===>> "; cin >> Number; PO << "Enter a number ===>> " << Number << endl; }
void DisplayData() { PO << endl << endl; PO << "The entered number is " << Number << endl; PO.close(); getch(); }
|
The main focus is on the EnterData function. You will notice a combination of conventional cout and cin statements combined with the PO statements. The PO statements will go to the monitor or to the printer depending on selection. The cout statement will surely always go to the monitor. This means that you will get the following two types of program output. The first output is the result of selecting monitor output. The second output is the result of selecting printer output.
|
PROG0819.CPP MONITOR OUTPUT
WHERE DO YOU WISH TO DIRECT PROGRAM OUTPUT?
[A] Monitor [B] Printer
PLEASE ENTER YOUR SELECTION ===>> A
Enter a number ===>> 1000 Enter a number ===>> 1000
The entered number is 1000
|
PROG0819.CPP PRINTER OUTPUT
THERE IS NO PRINTER OUTPUT
|
The double input statement is the result of one statement (with cout) that automatically goes to the monitor, and the echo statement, which is selected to go to the monitor. It looks a little strange, but it is better to see double on the monitor than to see nothing when you print.
PROG0819.CPP MONITOR OUTPUT
WHERE DO YOU WISH TO DIRECT PROGRAM OUTPUT?
[A] Monitor [B] Printer
PLEASE ENTER YOUR SELECTION ===>> B
Enter a number ===>> 1000
|
PROG0819.CPP PRINTER OUTPUT
Enter a number ===>> 1000
The entered number is 1000
|
The OutputSelection function always displays on the monitor. In this case the printer is selected and you will notice that there is now an input statement in both windows. The DisplayData output statement will only show up in the printer window.
This is one of those weird topics that probably does not benefit from additional explanation. It will probably only generate additional confusion. For many years, I have seen students struggle with this concept initially. Trust me, it only takes a few program assignments to realize what is happening.
8.10 Using User-Created Include Files
A few sections ago we investigated using functions for frequently used tasks. We will return to this topic and try to add some practical program techniques along the way. Imagine now that you are down the computer science road quite a distance. You have accumulated an impressive quantity of nifty functions that you use in many programs. You are proud of all you handy functions and you use them gladly and frequently. Imagine that you have a total of twenty functions
Now consider this. If you use twenty functions, these functions will occupy space on the monitor and certainly use up printing paper and printing time. You waste time fixing a program that includes the same functions, and your teacher has to grade a program that includes many functions that show up each and every time. There must be a better way.
The secret is to use an include file. You have been doing this with bunches of special Turbo C++ function libraries, and there is no reason why you cannot take advantage of this space saving feature yourself. Essentially, you place all your happy functions in a special utility file and include this file with any program that you write. You can now access any of the functions without actually having the functions show up in your current edit window.
That is the general idea of the include file. First, let us look at the syntax involved by using a small program that does little but allows you to concentrate on all the required components for using an include file. Program PROG0820.CPP calls function One and function Two. There is no evidence that these functions are defined anywhere. You do see that some file, PROG0820.INC, is included.
|
// PROG0820.CPP // This program demonstrates using an include file.
#include <iostream.h> #include <conio.h> #include "PROG0820.INC"
void main() { clrscr(); One(); Two(); getch(); }
|
The PROG0820.INC file is not a program. It is a file that contains two functions. The file ending .INC is not any type of C++ convention. It is strictly a Mr. Schram peculiarity to indicate that it is an include file.
|
// PROG0820.INC // This file is included by program PROG0820.CPP.
void One() { cout << endl << endl; cout << "THIS IS PROCEDURE ONE" << endl; } void Two() { cout << endl << endl; cout << "THIS IS PROCEDURE TWO" << endl; } |
The C++ compiler handles program statements in sequence. The compiler starts at the top of the program file. When the compiler encounters the preprocessor statement #include "PROG0820.INC", compiling stops, and the include file is then found and compiled next. After the include file is compiled, compiling continues with the statement immediately following the include statement.
|
Include File Placement Rule |
|
Include files are compiled at the exact location of the include preprocessor. Normally, the include statement is at the top of the program. However, it can be placed anywhere that a file needs to be included.
User-created include files require quotes like:
#include "UTILITY.INC"
File names are not case-sensitive. They can be lower case, upper case, or a combination. The convention at Berkner High School is to use UPPER CASE for user-created include files.
|
Creating a Utility Library
We now return to the concept of using a utility library of frequently used functions. This really is a combination of many topics in this chapter. Each one of the frequently used program segments or modules, is placed in a user-defined function. One of the functions is the OutputSelection function, discussed earlier and we will use the convenience of the include preprocessor so that the growing utility file does not need to be present in the editor file. Program PROG0821.CPP demonstrates the use of a small utility library. Keep in mind that this is only a start and your library will grow. Your program lab assignments and your teacher will give you additional information about include file requirements for your particular class.
|
// PROG0821.CPP // This program demonstrates using a utility library of // of frequently used functions.
#include "UTILITY.INC"
int Nr1,Nr2,Nr3; // three numbers to be averaged float Mean; // average of the three numbers
void EnterData(); void ComputeMean(); void DisplayData();
void main() { OutputSelection(); Heading(); Execution(); EnterData(); ComputeMean(); DisplayData(); Terminate(); }
void EnterData() { Skip4(); cout << "ENTER THREE INTEGERS ===>> "; cin >> Nr1 >> Nr2 >> Nr3; PO << "ENTER THREE INTEGERS ===>> " << Nr1 << " " << Nr2 << " " << Nr3 << endl; }
void ComputeMean() { Mean = (float) (Nr1 + Nr2 + Nr3) / 3; // without (float) you will get integer division }
void DisplayData() { Skip4(); PO << setprecision(4) << "MEAN: " << Mean << endl; }
|
|
PROG0821.CPP OUTPUT
WHERE DO YOU WISH TO DIRECT PROGRAM OUTPUT?
[A] Monitor [B] Printer
PLEASE ENTER YOUR SELECTION ===>> A
---------------------------------------------------- =============== EXECUTION BEGINS =============== ----------------------------------------------------
ENTER THREE INTEGERS ===>> 12 14 16 ENTER THREE INTEGERS ===>> 12 14 16
MEAN: 14
---------------------------------------------------- ============= EXECUTION TERMINATES ============= ----------------------------------------------------
|
Once again there are many function calls made whose details are not shown anywhere. Also remember that monitor output will cause a double line display. On the next page is the utility library file that has the implementations of each one of the frequently used functions. You will also notice that many include statements are part of the utility library. This feature is very convenient and saves a lot of time. You need to decide personally which function libraries are frequently used and you may decide to add these library include statements in your personal library of utility functions.
|
///////////////////////////////////////////////////////////////////////// // UTILITY.INC //////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // // Checked 12-21-99 by Leon Schram // Utility library functions for use in Chapter VIII only. // /////////////////////////////////////////////////////////////////////////
#include <iostream.h> // necessary for program input/output #include <conio.h> // necessary for screen operations like clrscr #include <iomanip.h> // necessary for output formats #include <fstream.h> // necessary for program output to the printer #include "BOOL.H" // allows boolean data type #include "APSTRING.H" // allows string operations
ofstream PO; // variable text file Program OutPut (PO)
// FUNCTION PROTOTYPES ///////////////////////////////////////////////
void ClearBuffer(); void OutputSelection(); void Heading(); void Skip2(); void Skip4(); void Execution(); void Terminate(); void Continue(); void SetStyle(); // FUNCTION IMPLEMENTATIONS //////////////////////////////////////////
void ClearBuffer() // Removes any "white-space" characters from the input-stream // buffer. Should be used after a cin statement. { apstring Dummy; getline(cin,Dummy); }
void OutputSelection() // Directs program execution output to monitor or to the printer. { clrscr(); char Choice; char FileName[12]; cout << "WHERE DO YOU WISH TO DIRECT PROGRAM OUTPUT?" << endl; cout << endl; cout << " [A] Monitor" << endl; cout << " [B] Printer" << endl; cout << endl; cout << "PLEASE ENTER YOUR SELECTION ===>> "; cin >> Choice; ClearBuffer(); switch(Choice) { case 'A': case 'a' : PO.open("CON"); break; case 'B': case 'b' : PO.open("PRN"); break; default : cout << "You must enter A or B" << endl; } }
void Heading() // Prints a student information heading at the start of the program. { PO << "************************************************************" << endl; PO << "************************************************************" << endl; PO << "** **" << endl; PO << "** NAME: Your first and last name **" << endl; PO << "** **" << endl; PO << "** COURSE: AP Computer Science I **" << endl; PO << "** **" << endl; PO << "** TEACHER: Your teacher's name **" << endl; PO << "** **" << endl; PO << "** PERIOD: Your class period **" << endl; PO << "** **" << endl; PO << "** ASSIGNMENT: Keyword Program #12 **" << endl; PO << "** **" << endl; PO << "** VERSION: 100 Points **" << endl; PO << "** **" << endl; PO << "** DATE DUE: Specify appropriate date **" << endl; PO << "** **" << endl; PO << "** TITLE: Brief description of program **" << endl; PO << "** **" << endl; PO << "** **" << endl; PO << "** PRESS <ENTER> TO CONTINUE PROGRAM EXECUTION **" << endl; PO << "** **" << endl; PO << "************************************************************" << endl; PO << "************************************************************" << endl; getch(); }
void Skip2() // Skips two lines. { PO << endl << endl; }
void Skip4() // Skips four lines. { PO << endl << endl << endl << endl; }
void Execution() // Displays Execution Begins messages at the start of program execution. { clrscr(); PO << endl << endl << endl << endl; PO << "---------------------------------------------------" << endl; PO << "=============== EXECUTION BEGINS ==============" << endl; PO << "---------------------------------------------------" << endl; }
void Terminate() // Displayes Execution Terminates at the conclusion of program execution. { PO << endl << endl << endl << endl; PO << "---------------------------------------------------" << endl; PO << "============= EXECUTION TERMINATES ============" << endl; PO << "---------------------------------------------------" << endl; PO << (char) 12; getch(); }
void Continue() // Stops program execution and waits for any key press. { cout << endl << endl; cout << "Press <Enter> to Continue"; getch(); }
void SetStyle() // Puts program output in floating point style with zeroes display. { PO << setiosflags(ios::showpoint); PO << setiosflags(ios::fixed); }
|
8.11 Header and Implementation Files
Observant students may have noticed something. The earlier chapters used a variety of include files like iostream.h, conio.h, and apstring.h. It seems that each one of the files ends with .h and you probably have heard the term header file used for such an include library. Now that you have created your own library file, it has the .inc ending. Well relax, there is no special magic in these endings, but there are good reasons to use header files.
Consider the OutputSelection function. Do you need to understand all the details of the complete function, to use the function? No, is the answer. You need to know what the function does and how the function is called. This means that all you need is the heading of a function and some appropriate comments to explain the function purpose.
There is a second benefit. Placing all the functions headings or proto-types closely together will give you a quicker overlook of the capabilities of the library file that you are including. Does this mean that the function implementation are completely ignored? Not exactly, because a function proto-type does a poor job without a complete function implementation located somewhere else. In our case the implementation files will be placed in a separate implementation file. This implementation file will have the same name as the header file, but it will have a *.CPP ending. This means that the earlier utility.inc file is now divided up into two separate files that will be shown in the next couple of pages.
|
Header Files and Implementation Files |
|
Function libraries are divided into two separate files: Header files, which stores all the function heading proto-types and other include libraries. Implementation files, which stores the details of the complete function implementations The header file ends with .H and has a name like UTILITY.H and includes the implementation file. The implementation file uses the same identifier as the header file and has a name like UTILITY.CPP.
|
|
///////////////////////////////////////////////////////////////////////// // UTILITY.H ///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // // Checked 06-30-99 by Leon Schram // Utility library functions for Chapter VIII. // A more permanent utility library will be presented in Chapter IX. // This is the header file of function proto-types. // /////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////// // Preprocessors, which prevent multiple inclusions of this file. // #ifndef _UTILITY_H #define _UTILITY_H
///////////////////////////////////////////////////////////////////////// // Include statements for the more common C++ function libraries. // #include <iostream.h> // necessary for program input/output #include <conio.h> // necessary for screen operations like clrscr #include <iomanip.h> // necessary for output formats #include <fstream.h> // necessary for program output to the printer #include "BOOL.H" // allows boolean data type #include "APSTRING.H" // allows string operations // /////////////////////////////////////////////////////////////////////////
ofstream PO; // variable text file Program OutPut (PO)
// FUNCTION PROTOTYPES //////////////////////////////////////////////////
void ClearBuffer(); // Removes any "white-space" characters from the input-stream // buffer. Should be used after a cin statement.
void OutputSelection(); // Directs program execution output to monitor or to the printer.
void Heading(); // Prints a student information heading at the start of the program.
void Skip2(); // Skips two lines.
void Skip4(); // Skips four lines.
void Execution(); // Displays Execution Begins messages at the start of program execution.
void Terminate(); // Displayes Execution Terminates at the conclusion of program execution.
void Continue(); // Stops program execution and waits for any key press.
void SetStyle(); // Puts program output in floating point style with zeroes display.
// FUNCTION IMPLEMENTATIONS //////////////////////////////////////////
// The function implementations are stored in the UTILITY1.CPP file. // This file is included by the statement below.
#include "UTILITY.CPP"
#endif
|
|
///////////////////////////////////////////////////////////////////////// // UTILITY.CPP //////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // // Checked 06-30-99 by Leon Schram // This is the implementation file of the UTILITY.H file. // This file is only used for Chapter VIII. // /////////////////////////////////////////////////////////////////////////
// FUNCTION IMPLEMENTATIONS //////////////////////////////////////////
void ClearBuffer() // Removes any "white-space" characters from the input-stream // buffer. Should be used after a cin statement. { apstring Dummy; getline(cin,Dummy); }
void OutputSelection() // Directs program execution output to monitor or to the printer. { clrscr(); char Choice; char FileName[12]; cout << "WHERE DO YOU WISH TO DIRECT PROGRAM OUTPUT?" << endl; cout << endl; cout << " [A] Monitor" << endl; cout << " [B] Printer" << endl; cout << endl; cout << "PLEASE ENTER YOUR SELECTION ===>> "; cin >> Choice; ClearBuffer(); switch(Choice) { case 'A': case 'a' : PO.open("CON"); break; case 'B': case 'b' : PO.open("PRN"); break; default : cout << "You must enter A or B" << endl; } }
void Heading() // Prints a student information heading at the start of the program. { PO << "************************************************************" << endl; PO << "************************************************************" << endl; PO << "** **" << endl; PO << "** NAME: Your first and last name **" << endl; PO << "** **" << endl; PO << "** COURSE: AP Computer Science I **" << endl; PO << "** **" << endl; PO << "** TEACHER: Your teacher's name **" << endl; PO << "** **" << endl; PO << "** PERIOD: Your class period **" << endl; PO << "** **" << endl; PO << "** ASSIGNMENT: Keyword Program #12 **" << endl; PO << "** **" << endl; PO << "** VERSION: 100 Points **" << endl; PO << "** **" << endl; PO << "** DATE DUE: Specify appropriate date **" << endl; PO << "** **" << endl; PO << "** TITLE: Brief program description **" << endl; PO << "** **" << endl; PO << "** **" << endl; PO << "** PRESS <ENTER> TO CONTINUE PROGRAM EXECUTION **" << endl; PO << "** **" << endl; PO << "************************************************************" << endl; PO << "************************************************************" << endl; getch(); }
void Skip2() // Skips two lines. { PO << endl << endl; }
void Skip4() // Skips four lines. { PO << endl << endl << endl << endl; }
void Execution() // Displays Execution Begins messages at the start of program execution. { clrscr(); PO << endl << endl << endl << endl; PO << "---------------------------------------------------" << endl; PO << "=============== EXECUTION BEGINS ==============" << endl; PO << "---------------------------------------------------" << endl; }
void Terminate() // Displayes Execution Terminates at the conclusion of program execution. { PO << endl << endl << endl << endl; PO << "---------------------------------------------------" << endl; PO << "============= EXECUTION TERMINATES ============" << endl; PO << "---------------------------------------------------" << endl; PO << (char) 12; getch(); }
void Continue() // Stops program execution and waits for any key press. { cout << endl << endl; cout << "Press <Enter> to Continue"; getch(); }
void SetStyle() // Puts program output in floating point style with zeroes display. { PO << setiosflags(ios::showpoint); PO << setiosflags(ios::fixed); }
|
We can test our new-and-improved utility library with the same kind of program that was used earlier to test utility1.inc. The test program has a new example number, PROG0822.CPP, because it needs to include the *.h file in place of the *.inc file. The program output will be precisely the same as the previous program example.
|
// PROG0822.CPP // This program demonstrates how to use the utility library // by including the header file, which in turn includes the // implementation file.
#include "UTILITY.H"
int Nr1,Nr2,Nr3; // three numbers to be averaged float Mean; // average of the three numbers
void EnterData(); void ComputeMean(); void DisplayData();
void main() { OutputSelection(); Execution(); EnterData(); ComputeMean(); DisplayData(); Terminate(); }
void EnterData() { Skip4(); cout << "ENTER THREE INTEGERS ===>> "; cin >> Nr1 >> Nr2 >> Nr3; PO << "ENTER THREE INTEGERS ===>> " << Nr1 << " " << Nr2 << " " << Nr3 << endl; }
void ComputeMean() { Mean = (float) (Nr1 + Nr2 + Nr3) / 3; // without (float) you will get integer division }
void DisplayData() { Skip4(); PO << setprecision(4) << "MEAN: " << Mean << endl; }
|
|
PROG0822.CPP OUTPUT
WHERE DO YOU WISH TO DIRECT PROGRAM OUTPUT?
[A] Monitor [B] Printer
PLEASE ENTER YOUR SELECTION ===>> A
---------------------------------------------------- =============== EXECUTION BEGINS =============== ----------------------------------------------------
ENTER THREE INTEGERS ===>> 12 14 16 ENTER THREE INTEGERS ===>> 12 14 16
MEAN: 14
---------------------------------------------------- ============= EXECUTION TERMINATES ============= ----------------------------------------------------
|