Pages

Showing posts with label C Plus Plus. Show all posts
Showing posts with label C Plus Plus. Show all posts

Saturday, April 23, 2016

C++ - Creating Functions

C++ - Creating Functions




In This Tutorial
• Writing functions
• Passing data to functions
• Naming functions with different arguments
• Creating function prototypes
• Working with include files


real-world programs can be many thousands (or millions!) of lines long. Developers need to break up these monster programs into smaller chunks that are easier to conceive, develop, and maintain. C++ allows programmers to divide their code into exactly such chunks (known as functions). As long as a function has a simple description and a well-defined interface to the outside world, it can be written and debugged without worrying about the code that surrounds it. This divide-and-conquer approach reduces the difficulty of creating a working program of significant size. This is a simple form of encapsulation

 Writing and Using a Function

Functions are best understood by example. This section starts with the example program FunctionDemo, which simplifies the NestedDemo program I discussed in Another Tutorial by defining a function to contain part of the logic. Then this section explains how the function is defined and how it is invoked, using FunctionDemo as a pattern for understanding both the problem and the solution.

The NestedDemo program contains an inner loop (which accumulates a sequence of numbers) surrounded by an outer loop (which repeats the process until the user quits). Separating the two loops would simplify the program by allowing the reader to concentrate on each loop independently. 

The following FunctionDemo program shows how NestedDemo can be simplified by creating the function sumSequence()

Tip:
Function names are normally written with a set of parentheses immediately following the term, like this: 


// FunctionDemo - demonstrate the use of functions
// by breaking the inner loop of the
// NestedDemo program off into its own
// function
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
// sumSequence - add a sequence of numbers entered from
// the keyboard until the user enters a
// negative number.
// return - the summation of numbers entered
int sumSequence(void)
{
// loop forever
int accumulator = 0;
for(;;)
{
// fetch another number
int value = 0;
cout << "Enter next number: ";
cin >> value;
// if it’s negative...
if (value < 0)
{
// ...then exit from the loop
break;
}
// ...otherwise add the number to the
// accumulator
accumulator= accumulator + value;
}
// return the accumulated value
return accumulator;
}
int main(int nNumberofArgs, char* pszArgs[])
{ 
cout << "This program sums multiple series\n"
<< "of numbers. Terminate each sequence\n"
<< "by entering a negative number.\n"
<< "Terminate the series by entering two\n"
<< "negative numbers in a row\n"
<< endl;
// accumulate sequences of numbers...
int accumulatedValue;
for(;;)
{
// sum a sequence of numbers entered from
// the keyboard
cout << "Enter next sequence" << endl;
accumulatedValue = sumSequence();
// terminate the loop if sumSequence() returns
// a zero
if (accumulatedValue == 0)
{
break;
}
// now output the accumulated result
cout << "The total is "
<< accumulatedValue
<< "\n"
<< endl;
}
cout << "Thank you" << endl;
// wait until user is ready before terminating program
// to allow the user to see the program results
system("PAUSE");
return 0;
}


Defining the sumSequence() function
The statement int sumSequence(void) begins the definition of the sumSequence() function. The block of code contained in the braces is the function body. The function sumSequence() accumulates a sequence of values entered from the keyboard. This code section is identical to that found in the inner loop of NestedDemo.

Calling the function sumSequence()
Let’s concentrate on the main program contained in the braces following main(). This section of code looks similar to the outer loop in NestedDemo.

The main difference is the expression accumulatedValue = sumSequence(); that appears where the inner loop would have been. The sumSequence() statement invokes the function of that name. A value returned by the function is stored in the variable accumulatedValue. Then this value is displayed. The main program continues to loop until sumSequence() returns a sum of zero, which indicates that the user has finished calculating sums.


Divide and conquer
The FunctionDemo program has split the outer loop in main() from the inner loop into a function sumSequence(). This division wasn’t arbitrary: sumSequence() performs a separate role — worth considering by itself — apart from the control features within FunctionDemo

Tip:
A good function is easy to describe. You shouldn’t have to use more than a single sentence, with a minimum of such words as and, or, unless, or but. For example, here’s a simple, straightforward definition: 


"The function sumSequence accumulates a sequence of integer values entered by the user." 

This definition is concise and clear. It’s a world away from the ContinueDemo program description:

"sums a sequence of positive values AND generates an error if the user enters a negative number AND displays the sum AND starts over again until the user enters two zero-length sums."

The output of a sample run of this program appears much like that generated by the NestedDemo program, as follows: 


--------------------------------------------------------------------------------------------------------------
This program sums multiple series
of numbers. Terminate each sequence 
by entering a negative number. 
Terminate the series by entering two
negative numbers in a row 

Enter next sequence
Enter next number: 1
Enter next number: 2  
Enter next number: 3
Enter next number: -1
The total is 6

Enter next sequence
Enter next number: 1
Enter next number: 2
Enter next number: -1
The total is 3 

Enter next sequence
Enter next number: -1
Thank you
Press any key to continue . . . 
--------------------------------------------------------------------------------------------------------------


Understanding the Details of Functions
Functions are so fundamental to creating C++ programs that getting a handle on the details of defining, creating, and testing them is critical. Armed with the example FunctionDemo program, consider the following definition of function

A function is a logically separated block of C++ code. The function construct has the following form: 

<return type> name(<arguments to the function>)
{
// ...
return <expression>;
}

The arguments to a function are values that can be passed to the function to
be used as input information. The return value is a value that the function
returns. For example, in the call to the function square(10), the value 10 is
an argument to the function square(). The returned value is 100.

Both the arguments and the return value are optional. If either is absent, the keyword void is used instead. That is, if a function has a void argument list, the function does not take any arguments when called (this was the case with the FunctionDemo program). If the return type is void, the function does not return a value to the caller

In the example FunctionDemo program, the name of the function is sumSequence(), the return type is int, and no arguments exist. 

Tip:
The default argument type to a function is void, meaning that it takes no arguments. A function
int fn(void) may be declared as int fn()

The function construct made it possible for me to write two distinct parts of the FunctionDemo program separately. I concentrated on creating the sum of a sequence of numbers when writing the sumSequence() function. I didn’t think about other code that may call the function. 

Similarly, when writing main(), I concentrated on handling the summation returned by sumSequence() while thinking only of what the function did  not how it worked. 


Understanding simple functions
The simple function sumSequence() returns an integer value that it calculates. Functions may return any of the regular types of variables. For example, a function might return a double or a char

If a function returns no value, the return type of the function is labeled void

Tip:
A function may be labeled by its return type — for example, a function that returns an int is often known as an integer function. A function that returns no value is known as a void function. 


For example, the following void function performs an operation, but returns no value: 

void echoSquare()
{
int value;
cout << “Enter a value:;
cin >> value;
cout << “\n The square is:<< (value * value) << “\n”;
return;
}

Control begins at the open brace and continues through to the return statement.
The return statement in a void function is not followed by a value. 

Tip:
The return statement in a void function is optional. If it isn’t present, execution returns to the calling function when control encounters the close brace

Understanding functions with arguments
Simple functions are of limited use because the communication from such functions is one-way — through the return value. Two-way communication is through function arguments.

Functions with arguments
A function argument is a variable whose value is passed to the calling function during the call operation. The following SquareDemo example program defines and uses a function square() that returns the square of a double precision float passed to it: 


// SquareDemo - demonstrate the use of a function
// which processes arguments
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
// square - returns the square of its argument
// doubleVar - the value to be squared
// returns - square of doubleVar
double square(double doubleVar)
{
return doubleVar * doubleVar;
}
// sumSequence - accumulate the square of the number
// entered at the keyboard into a sequence
// until the user enters a negative number
double sumSequence(void)
{
// loop forever
double accumulator= 0.0;
for(;;)
{
// fetch another number
double dValue = 0;
cout << "Enter next number: ";
cin >> dValue;
// if it’s negative...
if (dValue < 0)
{
// ...then exit from the loop 
break;
}
// ...otherwise calculate the square
double value = square(dValue);
// now add the square to the
// accumulator
accumulator= accumulator + value;
}
// return the accumulated value
return accumulator;
}
int main(int nNumberofArgs, char* pszArgs[])
{
cout << "This program sums multiple series\n"
<< "of numbers squared. Terminate each sequence\n"
<< "by entering a negative number.\n"
<< "Terminate the series by entering two\n"
<< "negative numbers in a row\n"
<< endl;
// Continue to accumulate numbers...
double accumulatedValue;
for(;;)
{
// sum a sequence of numbers entered from
// the keyboard
cout << "Enter next sequence" << endl;
accumulatedValue = sumSequence();
// terminate if the sequence is zero or negative
if (accumulatedValue <= 0.0)
{
break;
}
// now output the accumulated result
cout << "\nThe total of the values squared is "
<< accumulatedValue
<< endl;
}
cout << "Thank you" << endl;
// wait until user is ready before terminating program
// to allow the user to see the program results
system("PAUSE");
return 0;
}


This is the same FunctionDemo() program, except that SquareDemo() accumulates the square of the values entered. The function square() returns the value of its one argument multiplied by itself. The change to the sumSequence() function is simple — rather than accumulate the value entered, the function now accumulates the result returned from square()

Functions with multiple arguments
Functions may have multiple arguments that are separated by commas. Thus, the following function returns the product of its two arguments:

int product(int arg1, int arg2)
{
return arg1 * arg2; 
}


main() exposed
The "keyword" main() from our standard program template is nothing more than a function — albeit a function with strange arguments — but a function nonetheless. 

When a program is built, C++ adds some boilerplate code that executes before your program ever starts (you can’t see this code without digging into the bowels of the C++ library functions). This code sets up the environment in which your program operates. For example, this boilerplate code opens the default input and output channels cin and cout.

After the environment has been established, the C++ boilerplate code calls the function main(), thereby beginning execution of your code. When your program finishes, it exits from main(). This enables the C++ boilerplate to clean up a few things before turning control over to the operating system that kills the program. 

Overloading Function Names
C++ allows the programmer to assign the same name to two or more functions. This multiple use of names is known as overloading functions.

In general, two functions in a single program cannot share the same name. If they did, C++ would have no way to distinguish them. Note, however, that the name of the function includes the number and type of its arguments — but does not include its return argument. Thus the following are not the same functions: 

void someFunction(void)
{
// ....perform some function
}
void someFunction(int n)
{
// ...perform some different function
}
void someFunction(double d)
{
// ...perform some very different function
}
void someFunction(int n1, int n2)
{
// ....do something different yet 
}


C++ still knows that the functions someFunction(void)someFunction(int)someFunction(double), and someFunction(int, int) are not the same. Like so many things that deal with computers, this has an analogy in the human world.  

void as an argument type is optional. sumFunction(void) and sumFunction() are the same function. A function has a shorthand name, such as someFunction(), in same way that I have the shorthand name Stephen (actually, my nickname is Randy, but work with me on this one). If there aren’t any other Stephens around, people can talk about Stephen behind his back. If, however, there are other Stephens, no matter how handsome they might be, people have to use their full names — in my case, Stephen Davis. As long as we use the entire name, no one gets confused — however many Stephens might be milling around. Similarly, the full name for one of the someFunctions() is someFunction(int). As long as this full name is unique, no confusion occurs. 

The analogies between the computer world (wherever that is) and the human world are hardly surprising because humans build computers. (I wonder . . . if dogs had built computers, would the standard unit of memory be a gnaw instead of a byte? Would requests group in packs instead of queues?)

Here’s a typical application that uses overloaded functions with unique full names: 


int intVariable1, intVariable2; // equivalent to
// int Variable1;
// int Variable2;
double doubleVariable;
// functions are distinguished by the type of
// the argument passed 
someFunction(); // calls someFunction(void)
someFunction(intVariable1); // calls someFunction(int)
someFunction(doubleVariable); // calls someFunction(double)
someFunction(intVariable1, intVariable2); // calls
// someFunction(int, int)
// this works for constants as well
someFunction(1); // calls someFunction(int)
someFunction(1.0); // calls someFunction(double) 
someFunction(1, 2); // calls someFunction(int, int)


 In each case, the type of the arguments matches the full name of the three functions.

Warning:
The return type is not part of the extended name (which is also known as the function signature) of the function. The following two functions have the same name — so they can’t be part of the same program: 

int someFunction(int n); // full name of the function
// is someFunction(int)
double someFunction(int n); // same name

Remember:
You’re allowed to mix variable types as long as the source variable type is more restrictive than the target type.
Thus an int can be promoted to a double. The following is acceptable:

int someFunction(int n);
double d = someFunction(10); // promote returned value



The int returned by someFunction() is promoted into a double. Thus the
following would be confusing: 

int someFunction(int n);
double someFunction(int n);
double d = someFunction(10);// promote returned int?
// or use returned double as is

Here C++ does not know whether to use the value returned from the double
version of someFunction() or promote the value returned from int version

Defining Function Prototypes
The programmer may provide the remainder of a C++ source file, or module, the extended name (the name and functions) during the definition of the function.

The target functions sumSequence() and square() — appearing earlier in this Tutorial— are both defined in the code that appears before the actual call. This doesn’t have to be the case: A function may be defined anywhere in the module. (A module is another name for a C++ source file.) 

However, something has to tell the calling function the full name of the function to be called. Consider the following code snippet:  

int main(int nNumberofArgs, char* pszArgs[])
{
someFunc(1, 2);
}
int someFunc(double arg1, int arg2)
{
// ...do something
}


main() doesn’t know the full name of the function someFunc() at the time of
the call. It may surmise from the arguments that the name is someFunc(int, int)
and that its return type is void — but as you can see, this is incorrect.

I know, I know — C++ could be less lazy and look ahead to determine the full name of someFunc()s on its own, but it doesn’t. It’s like my crummy car; it gets me there, and I’ve learned to live with it. 

What is needed is some way to inform main() of the full name of someFunc() before it is used. This is handled by what we call a function prototype.



A prototype declaration appears the same as a function with no body. In use, a prototype declaration looks like this:

int someFunc(double, int);
int main(int nNumberofArgs, char* pszArgs[])
{
someFunc(1, 2);
}
int someFunc(double arg1, int arg2)
{
// ...do something
}

The prototype declaration tells the world (at least that part of the
world after the declaration) that the extended name for someFunc() is
someFunction(double, int). The call in main() now knows to cast
the 1 to a double before making the call. In addition, main() knows that
the value returned by someFunc() is an int. 

Variable Storage Types
Function variables are stored in three different places. Variables declared within a function are said to be local. In the following example, the variable localVariable is local to the function fn():


int globalVariable;
void fn()
{
int localVariable;
static int staticVariable;
}


The variable localVariable doesn’t exist until execution passes through
its declaration within the function fn(). localVariable ceases to exist
when the function returns. Upon return, whatever value that is stored in
localVariable is lost. In addition, only fn() has access to localVariable —
other functions cannot reach into the function to access it. 

By comparison, the variable globalVariable is created when the program begins execution — and exists as long as the program is running. All functions have access to globalVariable all the time. 

The static variable staticVariable is a sort of mix between a local and a global variable. The variable staticVariable is created when execution first reaches the declaration — at roughly when the function fn() is called. The variable is not destroyed when program execution returns from the function. If fn() assigns a value to staticVariable once, it’ll still be there the next time fn() is called. The declaration is ignored every subsequent time execution passes through. 

In case anyone asks, there is a fourth type, auto, but today it has the same meaning as local, so you rarely (if ever) see that declaration type anymore. So whoever asked you about it is probably just being a show off (or showing his age). 


Including Include Files
It’s common to place function prototypes in a separate file (called an include file) that the programmer can then include in her C++ source files. Doing so sets the stage for a C++ preprocessor program (which runs before the actual compiler takes over) to insert the contents of a file such as filename, at the point of a statement such as #include "filename"

A definition for a typical math include file looks like this:


// math include file:
// provide prototypes for functions that might be useful
// in more than one program
// abs - return the absolute value of the argument
double abs(double d);
// square - return the square of the argument
double square(double d);
A program uses the math include file like this: 
// MyProgram -
#include “math”
using namespace std;
// my code continues here


The #include directive says, in effect, Replace this directive with the contents
of the math file. 

The #include directive doesn’t have the format of a C++ statement because it’s interpreted by a separate interpreter that executes before the C++ compiler starts doing its thing. In particular, the # must be in column one and an end-of-line terminates the include statement. The actual file name must be enclosed in either quotes or brackets. Brackets are used for C++ library functions. Use the quotes for any includes that you create. 

The C++ environment provides include files such as cstdio and iostream. In fact, it’s iostream that contains the prototype for the setf() function used in Another Tutorial to set output to hex mode. 

Tip:
For years, programmers followed the custom of using the extension .h to designate include files. In more recent years, the C++ ISO standard removed the .h extension from standard include files. (For example, the include file cstdio was previously known as stdio.h.) Many programmers still stubbornly cling to the “.h gold standard” for their own programs. (What’s in a name? Evidence that even high-tech folks have traditions.) 

Friday, April 22, 2016

C++ - Declaring Variables Constantly

C++ - Declaring Variables Constantly



In This Tutorial

• Declaring variables
• Declaring different types of variables 
• Using floating-point variables
• Declaring and using other variable types


The most fundamental of all concepts in C++ is the variable — a variable is like a small box. You can store things in the box for later use, particularly numbers. The concept of a variable is borrowed from mathematics. A statement such as.

x = 1

stores the value 1 in the variable x. From that point forward, the mathematician can use the variable x in place of the constant 1 — until she changes the value of x to something else. 

Variables work the same way in C++. You can make the assignment.

x = 1;

From that point forward in the program, until the value of x is changed, any references to x are the same as referencing 1. That is, the value of x is 1.

Unfortunately, C++ has a few more concerns about variables than the mathematician does. This chapter deals with the care and feeding of variables in C++.

Declaring Variables
C++ saves numeric values in small storage boxes known as variables. Mathematicians throw variables around with abandon. A mathematician might (for example) write down something like the following:

(x + 2) = y / 2
x + 4 = y
solve for x and y

Any reader who’s had algebra realizes right off that the mathematician has introduced the variables x and y. But C++ isn’t that smart (computers may be fast, but they’re stupid).

You have to announce each variable to C++ before you can use it. You have to say something soothing like this

int x;
x = 10;

int y;                                                            
y = 5;

These lines of code declare that a variable x exists, that it is of type int, and that a variable y of type int also exists. (The next section discusses variable types.) You can declare variables (almost) anywhere you want in your program — as long as you declare the variable before you use it.

Declaring Different Types of Variables
If you’re on friendly terms with math (hey, aren’t we all?), you probably think of a variable in mathematics as an amorphous box capable of holding whatever you might choose to store in it. You might easily write something like the following:

x = 1
x = 2.3
x = "this is a sentence"
x = Texas

Alas, C++ is not that flexible. (On the other hand, C++ can do things that people can’t do, such as add a billion numbers or so in a second, so let’s not get too uppity.) To C++, there are different types of variables just as there are different types of storage bins. Some storage bins are so small that they can only handle a single number. It takes a larger bin to handle a sentence. Of course, no bin is large enough to hold Texas (maybe Rhode Island or Delaware).

You have to tell C++ what size bin you need before you can use a C++ variable. In addition, different types of variables have different properties. So far, you have only seen the int type of variable in this chapter:

int x;
x = 1;

The variable type int is the C++ equivalent of an integer — a number that has no fractional part. (Integers are also known as counting numbers or whole numbers.)

Integers are great for most calculations. You can make it up through most (if not all) of elementary school with integers. It isn’t until you reach age 11 or so that they start mucking up the waters with fractions. The same is true in C++: More than 90 percent of all variables in C++ are declared to be of type int.

Unfortunately, int variables don’t always work properly in a program. If (for example) you worked through the temperature-conversion program in Chapter 1, the program has a potential problem — it can only handle integer temperatures — whole numbers that don’t have a fractional part. This limitation of using only integers doesn’t affect daily use because it isn’t likely that someone (other than a meteorologist) would get all excited about entering a fractional temperature (such as 10.5 degrees). The lurking problem is not at all obvious: The conversion program lops off the fractional portion of temperatures that it calculates, and just keeps going without complaint. This can result in a lapse of accuracy that can be serious — for example, you wouldn’t want to come up a half mile short of the runway on your next airplane trip due to a navigational round-off.

Reviewing the limitations of integers in C++ 
The int variable type is the C++ version of an integer. int variables suffer the same limitations as their counting-number integer equivalents in math do.

Integer round-off
Consider the problem of calculating the average of three numbers. Given three int variables — nValue1, nValue2, and nValue3 — an equation for calculating the average is

int nAverage;
int nValue1;
int nValue2;
int nValue3;
nAverage = (nValue1 + nValue2 + nValue3) / 3;

Because all three values are integers, the sum is assumed to be an integer. Given the values 1, 2, and 2, the sum is 5. Divide that by 3, and you get 12⁄3, or 1.666. Given that all three variables nValue1, nValue2, and nValue3 are integers, the sum is also assumed to be an integer. The result of the division is also an integer. The resulting value of nAverage is unreasonable but logical: 1.

Lopping off the fractional part of a number is called truncation, or rounding off. For many applications, truncation isn’t a big deal. Some folks might consider its results reasonable (not mathematicians or bookies, of course), but integer truncation can create math mayhem in computer programs. Consider the following equivalent formulation:

int nAverage;
int nValue1;
int nValue2;
int nValue3;
nAverage = nValue1/3 + nValue2/3 + nValue3/3;

Plugging in the same 1, 2, and 2 values, the resulting value of nAverage is (talk about logical-but-unreasonable) 0. To see how this can occur, consider that 13 truncates to 0, 23 truncates to 0, and 23 truncates to 0. The sum of 0, 0, and 0 is zero. (Sort of like that old song: “Nothing from nothing leaves nothing, ya gotta be something . . .”) You can see that integer truncation can be completely unacceptable.

Limited range
A second problem with the int variable type is its limited range. A normal int variable can store a maximum value of 2,147,483,647 and a minimum value of –2,147,483,648 — roughly from positive 2 billion to negative 2 billion, for a total range of about 4 billion.

Tip:
Two billion is a very large number: plenty big enough for most uses. But it’s not large enough for some applications — for example, computer technology. In fact, your computer probably executes faster than 2 gigahertz, depending upon how old your computer is. (Giga is the prefix meaning billion.) A single strand of communications fiber — the kind that’s been strung from one end of the country to the other — can handle way more than 2 billion bits per second.

C++ offers a little help by allowing you declare an integer to be unsigned, meaning that it cannot be negative. An unsigned int value type can represent a number from 0 to 4,294,967,295, should the need arise for some unimaginable reason.

Tip:
You can declare a variable simply unsigned. The int is implied.

Solving the truncation problem 
The limitations of int variables can be unacceptable in some applications. Fortunately, C++ understands decimal numbers. A decimal number can have a nonzero fractional part. (Mathematicians also call those real numbers.) Decimal numbers avoid many of the limitations of int type integers. Notice that a decimal number “can have” a nonzero fractional part. In C++, the number 1.0 is just as much a decimal number as 1.5. The equivalent integer is written simply as 1. Decimals numbers can also be negative, like –2.3.

When you declare variables in C++ that are decimal numbers, you identify them as double precision floating-point values. (Yes, there is such a critter as a “single precision floating-point variable,” but stick with me here.) The term floating-point means the decimal point is allowed to float back and forth, identifying as many “decimal places” as necessary to express the value. Floatingpoint variables are declared in the same way as int variables:

double dValue1;

From this point forward, the variable dValue1 is declared to be a double. Once declared, you cannot change the type of a variable. dValue1 is now a double and will be a double for the remainder of its natural instructions. To see how floating-point numbers fix the truncation problem inherent with integers, convert all the int variables to double. Here’s what you get:

double dValue;
dValue = 1.0/3.0 + 2.0/3.0 + 2.0/3.0;

is equivalent to 

dValue = 0.333... + 0.666... + 0.666...;

which results in the value 

dValue = 1.666...;

Warning:
I have written the value 1.6666 . . . as if the number of trailing 6s goes on forever. This is (not necessarily) the case. There’s a limit to the number of digits of accuracy of a double variable — but it’s a lot more than I can keep track of.

Looking at the limits of floating-point numbers
Although floating-point variables can solve many calculation problems such as truncation, they have some limitations themselves — in effect, the reverse of those associated with integer variables. double variables can’t be used as counting numbers, they’re more difficult for the computer to handle, and they also suffer from round-off error (though not nearly to the same degree as int variables).

Counting
You cannot use floating-point variables in applications where counting is important. This includes C++ constructs, which requires counting ability. C++ can’t verify which whole number value is meant by a given floating-point number.

For example, it’s clear that 1.0 is 1. But what about 0.9 or 1.1? Should these also be considered as 1? C++ simply avoids the problem by insisting on using int values when counting is involved.

Calculation speed 
Historically, a computer processor can process integer arithmetic quicker than it can floating-point arithmetic. Thus, while a processor can add 1 million integer numbers in a given amount of time, the same processor may be able to perform only 200,000 floating-point calculations during the same period. (Not surprisingly, I couldn’t even get around to reading the first value.)

Calculation speed is becoming less of a problem as microprocessors increase their capabilities. Most modern processors contain special calculation circuitry for performing floating-point calculations almost as fast as integer calculations.

Loss of accuracy 
Floating-point variables cannot solve all computational problems. Floatingpoint variables have a limited precision of about 6 digits — an extra-economy size, double-strength version of float can handle some 15 significant digits with room left over for lunch.

To evaluate the problem, consider that 13 is expressed as 0.333 . . . in a continuing sequence. The concept of an infinite series makes sense in math, but not to a computer. The computer has a finite accuracy. Average 1, 2, and 2 (for example), and you get 1.666667.

C++ can correct for many forms of round-off error. For example, in output, C++ can determine that instead of 0.999999, that the user really meant 1. In other cases, even C++ cannot correct for round-off error.

Not-so-limited range 
Although the double data type has a range much larger than that of an integer, it’s still limited. The maximum value for an int is a skosh more than 2 billion. The maximum value of a double variable is roughly 10 to the 38th power. That’s 1 followed by 38 zeroes; it eats 2 billion for breakfast. (It’s even more than the national debt, at least at the time of this writing.)

Warning:
Only the first 13 digits or so have any meaning; the remaining 25 digits suffer from floating-point round-off error.

Declaring Variable Types
So far this chapter has been trumpeting that variables must be declared and that they must be assigned a type. Fortunately (ta-dah!), C++ provides a number of different variable types. See Table 2-1 for a list of variables, their advantages, and limitations.

C++ Variables 


It may seem odd that the standard floating length variable is called double while the “off size” is float. In days gone by, memory was an expensive asset — you could reap significant space savings by using a float variable. This is no longer the case. That, combined with the fact that modern processors perform double precision calculations at the same speed as float, makes the double the default. Bigger is better, after all.

The following statement declares a variable lVariable as type long and sets it equal to the value 1, while dVariable is a double set to the value 1.0:

// declare a variable and set it to 1
long lVariable;
lVariable = 1;

// declare a variable of type double and set it to 1.0
double dVariable;
dVariable = 1.0;

Tip:
You can declare a variable and initialize it in the same statement:

int nVariable = 1;     // declare a variable and
                       // initialize it to 1

Although such declarations are common, the only benefit to initializing a variable in the declaration is that it saves typing.

A char variable can hold a single character; a string (which isn’t really a variable but works like one for most purposes) holds a string of characters. Thus, ‘C’ is a char that contains the character C, whereas “C” is a string with one character in it. A rough analogy is that a ‘C’ corresponds to a nail in your hand, whereas “C” corresponds to a nail gun with one nail left in the magazine. (Chapter 9 describes strings in detail.)

Warning:
If an application requires a string, you’ve gotta provide one, even if the string contains only a single character. Providing nothing but the character just won’t do the job.

Types of constants
A constant is an explicit number or character (such as 1, 0.5, or ‘c’) that doesn’t change. As with variables, every constant has a type. In an expression such as n = 1; (for example), the constant 1 is an int. To make 1 a long integer, write the statement as n = 1L;. The analogy is as follows: 1 represents a single ball in the bed of a pickup truck, whereas 1L is a single ball in the bed of a dump truck. The ball is the same, but the capacity of its container is much larger.

Following the int to long comparison, 1.0 represents the value 1, but in a floating-point container. Notice, however, that the default for floating-point constants is double. Thus, 1.0 is a double number and not a float.

Warning:
true is a constant of type bool. However, “true” (note the quotation marks) is a string of characters that spell out the word true. In addition, in keeping with C++’s attention to case, true is a constant, but TRUE has no meaning.

Special characters
You can store any printable character you want in a char or string variable. You can also store a set of non-printable characters that is used as character constants. See Table 2-2 for a description of these important nonprintable characters.


You have already seen the newline character at the end of strings. This character breaks a string and puts the parts on separate lines. A newline character may appear anywhere within a string. For example,

"This is line 1\nThis is line 2"                                    

appears on the output as

This is line 1                                                      
This is line 2                                                      

Similarly, the \t tab character moves output to the next tab position. (This position can vary, depending on the type of computer you’re using to run the program.) Because the backslash character is used to signify special characters, a character pair for the backslash itself is required. The character pair \\ represents the backslash.



Are These Calculations Really Logical?
C++ provides a logical variable called bool. The type bool comes from Boolean, the last name of the inventor of the logical calculus. There are two values for a boolean variable: true and false.

Tip:
There are actually calculations that result in the value bool. For example, “x is equal to y” is either true or false.

Mixed Mode Expressions
C++ allows you to mix variable types in a single expression. That is, you are allowed to add an integer with a double precision floating-point value. In the following expression, for example, nValue1 is allowed to be an int:

// in the following expression the value of nValue1
// is converted into a double before performing the
// assignment int
nValue1 = 1;
nValue1 + 1.0;

An expression in which the two operands are not the same type is called a mixed-mode expression. Mixed-mode expressions generate a value whose type is equal to the more capable of the two operands. In this case, nValue1 is converted to a double before the calculation proceeds. Similarly, an expression of one type may be assigned to a variable of a different type, as in the following statement:

// in the following assignment, the whole
// number part of fVariable is stored into nVariable
double dVariable = 1.0;
int nVariable;
nVariable = dVariable;

Warning:
You can lose precision or range if the variable on the left side of the assignment is smaller. In the previous example, C++ truncates the value of before storing it in nVariable.

Converting a larger value type into a smaller value type is called demotion, whereas converting values in the opposite direction is known as promotion. Programmers say that the value of int variable nVariable1 is promoted to a double as expressions such as the following:

int nVariable1 = 1;
double dVariable = nVariable1;


Tip:
Mixed-mode expressions are not a good idea. Avoid forcing C++ to do your conversions for you.