Real-world programs aren’t usually that way. Programs that are big enough
to deal with the complexities of the real world are generally too large to write
in one single block of C++ instructions. Real-world programs are broken into
modules called functions in C++. This chapter introduces you to the wonderful world of functions.Breaking Your Problem
Down into FunctionsEven the Tire Changing Program from Chapter 1 was too big to write in asingle block. I only tackled the problem of removing the lug nuts. I didn’t
even touch the problem of jacking up the car, removing the wheel, getting the
spare out, and so on.
In fact, suppose that I were to take the lug nut removing code and put it into
a module that I call something fiendishly clever, like RemoveLugNuts(). (I add
the parentheses to follow C++ grammar.) I could bundle up similar modules
for the other functions.
118 Part III: Becoming a Functional ProgrammerThe resulting top-level module for changing a tire might look like the following:1. Grab spare tire;2. RaiseCar();
3. RemoveLugNuts(); // we know what this does
4. ReplaceWheel();
5. AttachLugNuts(); // inverse of RemoveLugNuts()
6. LowerCar();Only the first statement is actually an instruction written in Tire ChangingLanguage. Each of the remaining statements is a reference to a module
somewhere. These modules consist of sequences of statements written in
Tire Changing Language (including possible references to other, simpler
modules).
Imagine how this program is executed: The tire changing processor starts
at statement 1. First it sees the simple instruction Grab spare tire, which it
executes without complaint (it always does exactly what you tell it to do). It
then continues on to statement 2.
Statement 2, however, says, “Remember where you’re at and go find the set
of instructions called RaiseCar(). Once you’ve finished there, come back
here for further instructions.” In similar fashion, Statements 3 through 6 also
direct the friendly mechanically inclined processor off to separate sets of
instructions.Understanding How Functions
Are UsefulThere are several reasons for breaking complex problems up into simplerfunctions. The original reason that a function mechanism was added to early
programming languages was the Holy Grail of reuse. The idea was to create
functions that could be reused in multiple programs. For example, factorial
is a common mathematical procedure. If I rewrote the Factorial program as a
function, I could invoke it from any program in the future that needs to calculate a factorial. This form of reuse allows code to be easily reused from different programs as well as from different areas within the same program.
Once a function mechanism was introduced, however, people discovered
that breaking up large problems into simpler, smaller problems brought with
it further advantages. The biggest advantage has to do with the number of
things that a person can think about at one time. This is often referred to
as the “Seven Plus or Minus Two” Rule. That’s the number of things that a
person can keep active in his mind at one time. Almost everyone can keep at
Chapter 11: Functions, I Declare! 119least five objects in their active memory, but very few can keep more thannine objects active in their consciousness at one time.
You will have no doubt noticed that there are a lot of details to worry about
when writing C++ code. A C++ module quickly exceeds the nine-object upper
limit as it increases in size. Such functions are hard to understand and therefore to write and to get working properly.
It turns out to be much easier to think of the top-level program in terms of
high-level functionality, much as I did in the tire changing example at the
beginning of this chapter. This example divided the act of changing a tire into
six steps, implemented in five functions.
Of course, I still have to implement each of these functions, but these are much
smaller problems than the entire problem of changing a tire. For example, when
implementing RaiseCar(), I don’t have to worry about tires or spares, and I certainly don’t have to deal with the intricacies of loosening and tightening lug nuts.All I have to think about in that function is how to get the car off the ground.
In computer nerd-speak, we say that these different functions are written at
different levels of abstraction. The Tire Changing program is written at a veryhigh level of abstraction; the RemoveLugNuts() function in Chapter 1 is written at a low level of abstraction.Writing and Using a FunctionLike so many things, functions are best understood by example. The following code snippet shows the simplest possible example of creating and invoking a function:void someFunction(){
// do stuff
return;
}
int main(int nNumberofArgs, char* pszArgs[])
{
// do something
// now invoke someFunction()
someFunction();
// keep going here once control returns
}
120 Part III: Becoming a Functional ProgrammerThis example contains all the critical elements necessary to create andinvoke a function:1. The declaration: The first thing is the declaration of the function. Thisappears as the name of the function with a type in front followed by a
set of open and closed parentheses. In this case, the name of the function is someFunction(), and its return type is void. (I’ll explain whatthat last part means in the “Returning things” section of this chapter.)2. The definition: The declaration of the function is followed by the definition of what it does. This is also called the body of the function. Thebody of a function always starts with an open brace and ends with a
closed brace. The statements inside the body are just like those within a
loop or an if statement.3. The return: The body of the function contains zero or more returnstatements. A return returns control to immediately after the pointwhere the function was invoked. Control returns automatically if it ever
reaches the final closed brace of the function body.4. The call: A function is called by invoking the name of the function followed by open and closed parentheses.The flow of control is shown in Figure 11-1.Figure 11-1:Invokinga function
passes
control to
the module.
Control
returns to
immediately
after
the call.void someFunction()
{ | // do stuffreturn;2 | 1 |
{
// do something
// now invoke someFunction()
someFunction();
// keep going where once control returns
}3Returning thingsFunctions often return a value to the caller. Sometimes this is a calculatedvalue — a function like factorial() might return the factorial of a number.Sometimes this value is an indication of how things went — this is usually known
as an error return. So the function might return a zero if everything went OK, anda non-zero if something went wrong during the execution of the function.
Chapter 11: Functions, I Declare! 121To return a value from a function, you need to make two changes:1. Replace void with the type of value you intend to return.2. Place the value to return after the keyword return. C++ does not allowyou to return from a function by running into the final closed brace if the
return type is other than void.The keyword void is C++-ese for “nothing.” Thus a function declared with areturn type of int returns an integer. A function declared with a return typeof void returns nothing.Reviewing an exampleThe following FunctionDemo program uses the function sumSequence() tosum a series of numbers entered by the user at the keyboard. This function is
invoked repeatedly until the user enters a zero length sequence.//// FunctionDemo - demonstrate how to use a function
// to simplify the logic of the program.
//
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
//
// sumSequence() - return the sum of a series of numbers
// entered by the user. Exit the loop
// when the user enters a negative
// number.
int sumSequence()
{
// create a variable into which we will add the
// numbers entered by the user
int nAccumulator = 0;
for(;;)
{
// read another value from the user
int nValue;
cout << “Next: “;
cin >> nValue;
// exit if nValue is negative
if (nValue < 0)
{
break;
}
122 Part III: Becoming a Functional Programmer// add the value entered to the accumulated valuenAccumulator += nValue;
}
// return the accumulated value to the caller
return nAccumulator;
}
int main(int nNumberofArgs, char* pszArgs[])
{
cout << “This program sums sequences of numbers.\n”
<< “Enter a series of numbers. Entering a\n”
<< “negative number causes the program to\n”
<< “print the sum and start over with a new\n”
<< “sequence. “
<< “Enter two negatives in a row to end the\n”
<< “program.” << endl;
// stay in a loop getting input from the user
// until he enters a negative number
for(;;)
{
// accumulate a sequence
int nSum = sumSequence();
// if the sum is zero...
if (nSum == 0)
{
// ...then exit the program
break;
}
// display the result
cout << “Sum = “ << nSum << endl;
}
// wait until user is ready before terminating program
// to allow the user to see the program results
system(“PAUSE”);
return 0;
}First, concentrate on the main() program. After outputting rather verboseinstructions to the user, the program enters a for loop.A for loop whose conditional expression is empty (as in for(;;)) will loopforever unless something within the body of the loop causes control to exit
the loop (or until Hell freezes over).
Chapter 11: Functions, I Declare! 123The first non-comment line within this loop is the following:int nSum = sumSequence();This expression passes control to the sumSequence() function. Once control returns, the declaration uses the value returned by sumSequence() toinitialize nSum.The function sumSequence() first initializes nAccumulator to zero. It thenprompts the user for value from the keyboard. If the number entered is not
negative, it is added to the value in nAccumulator, and the user is promptedfor another value in a loop. As soon as the user enters a negative number, the
function breaks out of the loop and returns the value accumulated in nAccumulator to the caller.The following is a sample run from the FunctionDemo program:This program sums sequences of numbers.Enter a series of numbers. Entering a
negative number causes the program to
print the sum and start over with a new
sequence. Enter two negatives in a row to end the
program.
Next: 5Next: 15Next: 20Next: -1Sum = 40Next: 1Next: 2Next: 3Next: 4Next: -1Sum = 10Next: -1Press any key to continue . . .Passing Arguments to FunctionsFunctions that do nothing but return a value are of limited value because thecommunication is one-way — from the function to the caller. Two-way communication requires function arguments, which I discuss next.124 Part III: Becoming a Functional ProgrammerFunction with argumentsA function argument is a variable whose value is passed to the function duringthe call. The following FactorialFunction converts the previous factorial operation into a function://// FactorialFunction - rewrite the factorial code as
// a separate function.
//
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
//
// factorial - return the factorial of the argument
// provided. Returns a 1 for invalid arguments
// such as negative numbers.
int factorial(int nTarget)
{
// start with an accumulator that’s initialized to 1
int nAccumulator = 1;
for (int nValue = 1; nValue <= nTarget; nValue++)
{
nAccumulator *= nValue;
}
return nAccumulator;
}
int main(int nNumberofArgs, char* pszArgs[])
{
cout << “This program calculates factorials”
<< “ of user input.\n”
<< “Enter a negative number to exit” << endl;
// stay in a loop getting input from the user
// until he enters a negative number
for (;;)
{
// enter the number to calculate the factorial of
int nValue;
cout << “Enter number: “;
cin >> nValue;
// exit if the number is negative
if (nValue < 0)
Chapter 11: Functions, I Declare! 125{break;
}
// display the result
int nFactorial = factorial(nValue);
cout << nValue << “ factorial is “
<< nFactorial << endl;
}
// wait until user is ready before terminating program
// to allow the user to see the program results
system(“PAUSE”);
return 0;
}The declaration of factorial() includes an argument nTarget of int.Looking ahead, you can see that this is intended to be the value to calculate
the factorial of. The return value of the function is the calculated factorial.
In main(), the program prompts the user for a value, which it stores innValue. If the value is negative, the program terminates. If not, it callsfactorial() passing the value of nValue. The program stores the returnedvalue in nFactorial. It then outputs both values before returning to promptthe user for a new value.Functions with multiple argumentsA function can have multiple arguments by separating them by commas.Thus, the following function returns the product of two integer arguments:int product(int nValue1, int nValue2){
return nValue1 * nValue2;
}Exposing main()Now the truth can be told: The “keyword” main() from our standard template is nothing more than a function — albeit a function with strange arguments, but a function nonetheless.126 Part III: Becoming a Functional ProgrammerOverloading function namesC++ allows the programmer to assign the same name to two or more functions if the functions can be distinguished by either the number or types of arguments. This is called functionoverloading. Consider the following example functions:void someFunction(){
// ...perform some function
}
void someFunction(int nValue)
{
// ...perform some other function
}
void someFunction(char cValue)
{
// ...perform a function on characters
}
int main(int nNumberofArgs, char* pszArgs[])
{
someFunction(); // call the first function
someFunction(10); // call the second function
someFunction(‘a’); // now the third function
return 0;
}By comparing each of the preceding calls with the declarations, it is clear which function is meant
by each call. Because of this, C++ aficionados include the type of arguments with the name of the
function in what is called the function’s extended name or signature. Thus, the extended names
of the three functions are, in fact, different: someFunction(), someFunction(int), andsomeFunction(char).Warning: Notice that the return type is not part of the extended name and cannot be used to differentiate functions.When a program is built, C++ adds some boilerplate code that executesbefore your program ever gains control. This code sets up the environment
in which your program will operate. For example, this boilerplate code opens
the default input and output channels and attaches them to cin and cout.After the environment has been established, the C++ boilerplate code calls
the function main(), thereby beginning execution of your code. When yourprogram finishes, it returns from main(). This enables the C++ boilerplateto clean up a few things before terminating the program and handing control
back over to the operating system.
Chapter 11: Functions, I Declare! 127
Defining Function Prototype DeclarationsThere’s a little more to the previous program examples than meets the eye.Consider the second program, FactorialFunction, for example. During the
build process, the C++ compiler scanned through the file. As soon as it came
upon the factorial() function, it made a note in an internal table somewhere in the function’s extended name and its return type. This is how thecompiler was able to understand what I was talking about when I invoked thefactorial() function later on in main() — it saw that I was trying to calla function, and it said, “Let me look in my table of defined functions for one
called factorial(). Aha, here’s one!”In this case, the function was defined and the types and number of arguments
matched perfectly, but that isn’t always the case. What if I had invoked the
function not with an integer but with something that could be converted into
an integer? Suppose I had called the function as follows:factorial(1.1);That’s not a perfect match, 1.1 is not an integer, but C++ knows howto convert 1.1 into an integer. So it could make the conversion and usefactorial(int) to complete the call. The question is, does it?The answer is “Yes.” C++ will generate a warning in some cases to let you
know what it’s doing, but it will generally make the necessary type conversions to the arguments to use the functions that it knows about.Note: I know that I haven’t discussed the different variable types and won’t untilChapter 14, but the argument I am making is fairly generic. You will also see in
Chapter 14 how to avoid warnings caused by automatic type conversions.
What about a call like the following:factorial(1, 2);There is no conversion that would allow C++ to lop off an argument and usethe factorial(int) function to satisfy this call, so C++ generates an errorin this case.
The only way C++ can sort out this type of thing is if it sees the function declaration before it sees the attempt to invoke the function. This means each
function must be declared before it is used.
I know what you’re thinking (I think): C++ could be a little less lazy and look
ahead for function declarations that occur later on before it gives up and
starts generating errors, but the fact is that it doesn’t. It’s just one of those
things, like my crummy car; you learn to live with it.
128 Part III: Becoming a Functional ProgrammerSo does that mean you have to define all of your functions before you canuse them? No. C++ allows you to declare a function without a body in what is
known as a prototype declaration.A prototype declaration creates an entry for the function in the table I was
talking about. It fills in the extended name, inc luding the number and type of
the arguments, and the return type. C++ leaves the definition of the function,
the function body, empty until later.
In practice, a prototype declaration appears as follows:// the prototype declarationint factorial(int nTarget);
int main(int nNumberofArgs, char* pszArgs[])
{
cout << “The factorial of 10 is “
<< factorial(10) << endl;
return 0;
}
// the definition of the factorial(int) function;
// this satisfies our promise to provide a definition
// for the prototype function declaration above
int factorial(int nTarget)
{
// start with an accumulator that’s initialized to 1
int nAccumulator = 1;
for (int nValue = 1; nValue <= nTarget; nValue++)
{
nAccumulator *= nValue;
}
return nAccumulator;
}The prototype declaration tells the world (or at least that part of the worldafter the declaration) that factorial() takes a single integer argumentand returns an integer. That way, C++ can check the call in main() againstthe declaration to see whether any type conversions need to take place or
whether the call is even possible.
The prototype declaration also represents a promise to C++ to provide a
complete definition of factorial(int) somewhere else in the program. Inthis case, the full definition of factorial(int) follows right after main().It is common practice to provide prototype declarations for all functions defined
within a module. That way, you don’t have to worry about the order in which
they are defined. I’ll have more to say about this topic in the next chapter.
Chapter 12Dividing Programs into ModulesIn This Chapter▶ Breaking programs down into functions▶ Writing and using functions▶ Returning values from a function▶ Passing values to a function▶ Providing a function prototype declarationIn Chapter 11, I show you how to divide a complex problem into a number of separate functions; it is much easier to write and get a number ofsmaller functions to work than one large, monolithic program. Oftentimes,
however, you may want to reuse the functions you create in other applications. For example, I could imagine reusing the factorial() function I created in Chapter 11 in the future.One way to reuse such functions is to copy-and-paste the source code for
the factorial() function into my new program. However, it would be a loteasier if I could put the function in a separate file that I could then link into
future applications. Breaking programs into separate source code modules is
the subject of this chapter.Breaking Programs ApartThe programmer can break a single program into separate source files generally known as modules. These modules are compiled into machine code bythe C++ compiler separately and then combined during the build process to
generate a single program.
The process of combining separately compiled modules into a single program is called linking.130 Part III: Becoming a Functional ProgrammerBreaking programs into smaller, more manageable pieces has several advantages. First, breaking a program into smaller modules reduces the compiletime. Code::Blocks takes only a few seconds to gobble up and digest the programs that appear in this book. Very large programs can take quite a while,
however. I have worked on projects that took most of the night to rebuild.
In addition, recompiling all of the source code in the project just because one
or two lines change is extremely wasteful. It’s much better to recompile just
the module containing the change and then relink it into all of the unchanged
modules to create a new executable with the change. (The updated module
may contain more than just the one changed function but not that many more.)
Second, it’s easier to comprehend and, therefore, easier to write and debug
a program that consists of a number of well thought out but quasi-independent modules, each of which represents a logical grouping of functions. A
large, single source module full of all the functions that a program might use
quickly becomes hard to keep straight.
Third is the much vaunted specter of reuse. A module full of reusable functions that can be linked into future programs is easier to document and
maintain. A change in the module to fix some bug is quickly incorporated into
other executables that use that module.
Finally, there’s the issue of working together as a team. Two programmers
can’t work on the same module (at least not very well). An easier approach
is to assign one set of functions contained in one module to a programmer
while assigning a different set of functions in a different module to a second
programmer. The modules can be linked together when ready for testing.Breaking Up Isn’t That Hard to DoI can’t really include a large program in a book like this . . . well, I could, butthere wouldn’t be enough left for anything else. I will use the FactorialFunction
demo from Chapter 11 as my example large-scale program. In this section, I
will create the FactorialModule project that separates the program into several source modules. To do this, I will perform the following steps:
1. Create the FactorialModule project.
This is no different than creating any of the other project files up to this
point in the book.
2. Create the Factorial.cpp file to contain the factorial function.3. Create the Factorial.h include file (whatever that is) to be used by allmodules that want to call.
4. Update main.cpp to use the factorial() function.Chapter 12: Dividing Programs into Modules 131Creating Factorial.cppThe initial console application project created by Code::Blocks has only onesource file, main.cpp. The next step is to create a second source file thatwill contain the factorial function.
Follow these steps to create factorial.cpp containing the factorial()function:1. Select File➪New➪File.Code::Blocks responds by opening the window shown in Figure 12-1showing the different types of files you can add.Figure 12-1:The NewFile wizard
provides
you help
in adding
source files
to your
project.2. Select C/C++ Source and then click Go.This opens up a box warning that you are about to enter the mysteriousand dangerous Source File Wizard.3. Click Next.This will open the Source File Wizard.4. Click the ... next to the Filename with Full Path prompt.A File Open dialog box appears, allowing you to navigate to a differentfolder if you want to keep your source files in different directories. But
don’t make it any more complicated than it has to be.5. Enter factorial.cpp as the name of the source file and click Save.132 Part III: Becoming a Functional Programmer6. You want this file added to all executables that you create, so selectAll for the build targets.When you are finished, the dialog box should look like Figure 12-2.Figure 12-2:The C/C++Source
File dialog
box lets
you enter
the name
of the new
module,factorial.cpp.7. Click Finish to create Factorial.cpp and add it to the Project.The project file includes the list of all source files that it takes to buildyour program.8. Update factorial.cpp as follows://// factorial - this module includes the factorial function
//
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
#include “factorial.h”
//
// factorial - return the factorial of the argument
// provided. Returns a 1 for invalid arguments
// such as negative numbers.
int factorial(int nTarget)
{
// start with an accumulator that’s initialized to 1
int nAccumulator = 1;
for (int nValue = 1; nValue <= nTarget; nValue++)
{
Chapter 12: Dividing Programs into Modules 133nAccumulator *= nValue;}
return nAccumulator;
}The first four lines are part of the standard template used for all C++ sourcefiles in this book. The next line is the factorial.h include file, which I discuss further later in this chapter. This is followed by the factorial() function much as it appeared in Chapter 11.Include files don’t follow the same grammar rules as C++. For example, unlike
other statements in C++, the #include must start in column 1 and doesn’trequire a semicolon at the end.
Don’t try to compile factorial.cpp, as you haven’t created factorial.hyet.Creating an #include fileThe next step in the process is to create an include file. Okay, what’s aninclude file?
As I discuss in Chapter 11, the prototype declaration describes the functions
to be called by providing the number and types of arguments and the type of
the return value. Every function that you invoke must have a prototype declaration somewhere before the call.
It is possible to list out the prototype declarations manually for each function
you intend to use, but fortunately that isn’t necessary. Instead C++ allows the
same dummy who created the function to create an include file that contains
the function’s prototype declarations. This file can then be included in the
source files of the modules where the functions are called.
There are (at least) two ways to include these prototypes. One way is to copy
the contents of the include file and paste them into the module where the
calls are made. This isn’t a very good idea, however. For one thing, it is really
laborious. For another, if the prototype declaration for any one of the functions
in the include file is changed, the programmer will have to go through every
place the include file is used, delete the old one, and repaste in the new file.
Rather than do that, C++ includes a preprocessor that understands very
few instructions. Each of these instructions starts with a pound sign (#) in
column 1 followed immediately by a command. (Preprocessor commands
also end at the end of the line and don’t require a semicolon.)
134 Part III: Becoming a Functional ProgrammerThe most common preprocessor command is #include “filename.h”.This command copies and pastes the contents of filename.h at the point ofthe #include to create what is known as an intermediate source file. The preprocessor then passes this intermediate source file on to the C++ compilerfor processing. This process is shown graphically in Figure 12-3.Figure 12-3:The preprocessorinserts the
contents of
an include
file at the
point of the#includecommandbefore
passing
the results
to the C++
compiler.factorial.h:Preprocessor
main.cpp:int factorial(int nTarget);Intermediate file sent to C++ compilerusing namespace std;
int factorial(int nTarget);
int main(int nNumberofArgs, char* pszArgs[])
{
for (;;)
{
using namespace std; // ,,,file continues...
#include "factorial.h"
int main(int nNumberofArgs, char* pszArgs{})
{
for (;;)
{
// ,,,file continues...Including #include filesThe Code::Blocks wizard makes creating an include file painless. Just executethe following steps:1. Select File➪New➪File.Code::Blocks responds by opening the window shown in Figure 12-1 justas before. This time you’re creating an include file.2. Select Include File and then click Go.3. In the next window that warns you’re about to enter the Include File
Wizard, click Next.
4. Click the ... next to the Filename with Full Path prompt.A File Open dialog box appears.5. Enter factorial.h as the name of the include file and click Save.6. You want this file added to all executables that you create, so select
All for the build targets.When you are finished, the dialog box should look like Figure 12-4.Chapter 12: Dividing Programs into Modules 135Figure 12-4:The C/C++Header File
dialog box
lets you
enter the
name of the
new include
file module,factorial.h.7. Click Finish to create an empty include file that looks like the following:#ifndef FACTORIAL_H_INCLUDED#define FACTORIAL_H_INCLUDED
#endif // FACTORIAL_H_INCLUDED8. Edit the include file by adding the prototype for the factorial()function as follows:#ifndef FACTORIAL_H_INCLUDED#define FACTORIAL_H_INCLUDED
int factorial(int nTarget);
#endif // FACTORIAL_H_INCLUDED9. Click File Save.You’re done!Notice that the include file has been added to the project description in the
Management tab of Code::Blocks. This indicates that Code::Blocks will automatically rebuild the application if the include file changes.
Why include factorial.h in factorial.cpp? After all, factorial()doesn’t require a prototype of itself. You do this as a form of error checking.C++ will generate an error message when compiling factorial.cpp if theprototype declaration in factorial.h does not match the definition of thefunction. This ensures that the prototype declaration being used by other
source code modules matches the function definition.
136 Part III: Becoming a Functional ProgrammerCreating main.cppYou’re almost there: Open main.cpp and edit it to look like the following://// FactorialModule - rewrite the factorial code as
// a separate function in its own module.
//
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
#include “factorial.h”
int main(int nNumberofArgs, char* pszArgs[])
{
cout << “This program calculates factorials”
<< “ of user input.\n”
<< “Enter a negative number to exit” << endl;
// stay in a loop getting input from the user
// until he enters a negative number
for (;;)
{
// enter the number to calculate the factorial of
int nValue;
cout << “Enter number: “;
cin >> nValue;
// exit if the number is negative
if (nValue < 0)
{
break;
}
// display the result
int nFactorial = factorial(nValue);
cout << nValue << “ factorial is “
<< nFactorial << endl;
}
// wait until user is ready before terminating program
// to allow the user to see the program results
system(“PAUSE”);
return 0;
}This version of main.cpp looks identical to the FactorialFunction versionexcept that the definition of the factorial() function has been removedand the #include “factorial.h” added.Chapter 12: Dividing Programs into Modules 137Building the resultNow you can build the program (by selecting Build➪Build). Notice in theoutput messages that the compiler now compiles two files, main.cpp andfactorial.cpp. This is then followed by a single link step.When executed, the output from this version is indistinguishable from earlier
versions as demonstrated by the following test output:This program calculates factorials of user input.Enter a negative number to exit
Enter number: 55 factorial is 120Enter number: 66 factorial is 720Enter number: -1Press any key to continue . . .Using the Standard C++ LibraryNow you can see why the standard C++ template includes the directives#include <cstdio>#include <cstdlib>
#include <iostream>These include files contain the prototype declarations for functions providedby C++ as part of its standard library of routines (like cin >>, for example).Notice that the standard C++ library include files are included in angle brackets (<>), while I included my user-defined include file in quotes (“”). The only
difference between the two is that C++ looks for files contained in quotes
starting with the “current” directory (the directory containing the project
file), while C++ begins searching for bracketed files in the C++ include file
directories.
The online help files (at www.cppreference.com/wiki/) are a good sourceof information about the functions that make up the Standard C++ Library.Variable ScopeVariables are also assigned a storage type depending upon where and howthey are defined, as shown in the following snippet:
138 Part III: Becoming a Functional Programmerint nGlobalVariable;void fn()
{
int nLocalVariable;
static int nStaticVariable = 1;
nStaticVariable = 2;
}Variables defined within a function like nLocalVariable don’t exist untilcontrol passes through the declaration. In addition, nLocalVariable is onlydefined within fn() — the variable ceases to exist when control exits thefn() function.By comparison, the variable nGlobalVariable is created when the program begins execution and exists as long as the program is running. All functions have access to nGlobalVariable all the time.We say that nLocalVariable has local scope, and nGlobalVariable hasglobal scope.The keyword static can be used to create a sort of mishling — somethingbetween a global and a local variable. The static variable nStaticVariableis created when execution reaches the declaration the first time that functionfn() is called. Unlike nLocalVariable, however, nStaticVariable isnot destroyed when program execution returns from the function. Instead, it
retains its value from one call to the next.
In this example, nStaticVariable is initialized to 1 the first time that fn()is called. The function changes its value to 2. nStaticVariable retains thevalue 2 on every subsequent call — it is not reinitialized once it has been created. The initialization portion of the declaration is ignored every subsequent
time that fn() is called after the first time.However, the scope of nStaticVariable is still local to the function. Codeoutside of fn() does not have access to nStaticVariable.Global variables are useful for holding values that you want all functions to
have access to. Static variables are most useful for counters — for example,
if you want to know how many times a function is called. However, most variables are of the plain ol’ local variety.
No comments:
Post a Comment