Saturday, September 29, 2007

Quicksort Algorithm

Algorithm QuickSort(p,q)
//Sorts the elements a[p],.......,a[q] which resides in the global
//array a[1:n] into ascending order; a[n+1] is considered
//to be defined and must be >= all the elements in a[1:n].
{
if(p < q) then //If there are more than one element.
{
//divide P into two subproblems.

j:=Partition(a,p,q+1);

//j is the position of the partioning elements
//Solving the subproblems.
QuickSort(p,j-1);
QuickSort(j+1,q);
//Thereis no needfor combining solutions.
}
}

Algorithm Partition(a,m,p)
//Within a[m],a[m+1],....,a[p-1] the element are rearranged in such a manner that
//if initially t=a[m], and p-1, a[k]<=t for m<=k=t
//for q < k < p. q is returned.Set a[p]=infinity.

{
v:=a[m];i:=m; j:=p;
repeat
{
repeat
i:=i+1;
until(a[i]>=v);

repeat
j:=j-1;
until(a[j]<=v);

if(i }until(i>=j);

a[m]:=a[j]; a[j]:=v; return j;
}

Algorithm Interchange(a,i,j)
//Exchange a[i] with a[j]
{
p:=a[i];
a[i]:=a[j];
a[j]:=p;
}

Algorithm for MergeSort

Algorithm MergeSort(low,high)

//a[low:high] is a global array to be sorted.

//Small(P) is true if there is lnly one element

//to sort. In this case the list is already sorted

{

if(low < high) then // If there are more than one element.
{

//Divide P into subproblems.

//Find where to split the set.

mid:=[(low+high)/2];

//Solve the subproblems.

MergeSort(low,mid);

MergeSort(mid+1,high);

//Combine the solutions.

Merge(low,mid,high);

}

}





Algorithm Merge(low,mid,high)

//a[low:high] is a global array containing two sorted

//subsets in a[low:mid] and in a[mid+1:high]. The goal is to merge these two sets into

//a single set residing.

//in a[low:high]/ b[] is an auziliary global array.

{

h:=low; i:=low; j:=mid+1;

while((h<=mid) and j<=high)) do

{

if(a[h]<=a[j]) then

{

b[i]:=a[h]; h:=h+1;

}

else

{

b[i]:=a[j]; j:=j+1;

}

i:=i+1;

}



if(h>mid) then

for k:=j to high do

{

b[i]:=a[k]; i:=i+1;

}

else

for k:=h to mid do

{

b[i]:=a[k]; i:=i+1;

}

for k:=low to high do a[k]:=b[k];

}

Thursday, September 27, 2007

Decisions and Loops

Decisions and Loops
In this chapter, we will look at how to add decision-making capabilities to your C++ programs. You will also learn how to make your programs repeat a set of actions until a specific condition is met. This will enable you to handle variable amounts of input, as well as make validity checks on the data that you read in. You will also be able to write programs that can adapt their actions depending on the input data, and to deal with problems where logic is fundamental to the solution. By the end of this chapter you will have learnt:
How to compare data values
How to alter the sequence of program execution based on the result
What logical operators and expressions are and how you can apply them
How to deal with multiple choice situations
How to write and use loops in your programs
We will start with one of the most powerful programming tools: the ability to compare variables and expressions with other variables and expressions and, based on the outcome, execute one set of statements or another.

Understanding Scope

Understanding Scope
All variables have a finite lifetime when your program executes. They come into existence from the point at which you declare them and then, at some point, they disappear - at the latest, when your program terminates. How long a particular variable lasts is determined by a property called its storage duration. There are three different kinds of storage duration that a variable can have:
automatic storage duration
static storage duration
dynamic storage duration
Which of these a variable will have depends on how you create it. We will defer discussion of variables with dynamic storage duration until Chapter 3, but we can look into the characteristics of the other two in this chapter.
Another property that variables have is scope. The scope of a variable is simply that part of your program in which the variable name is valid. Within a variable's scope, you can legally refer to it, to set its value or use it in an expression. Outside of the scope of a variable, you cannot refer to its name - any attempt to do so will cause a compiler error. Note that a variable may still exist outside of its scope, even though you cannot refer to it by name. We will see examples of this situation a little later in this discussion.
All of the variables that we have declared up to now have had automatic storage duration, and are therefore called automatic variables. Let's take a closer look at these first.
Automatic Variables
The variables that we have declared so far have been declared within a block - that is, within the extent of a pair of curly braces. These are called automatic variables and are said to have local scope or block scope. An automatic variable is 'in scope' from the point at which it is declared until the end of the block containing its declaration.
An automatic variable is 'born' when it is declared and automatically ceases to exist at the end of the block containing the declaration. This will be at the closing brace matching the first opening brace that precedes the declaration of the variable. Every time the block of statements containing a declaration for an automatic variable is executed, the variable is created anew, and if you specified an initial value for the automatic variable, it will be reinitialized each time it is created.
There is a keyword, auto, which you can use to specify automatic variables, but it is rarely used since it is implied by default. Let's put together an example of what we've discussed so far.
Try It Out - Automatic Variables
We can demonstrate the effect of scope on automatic variables with the following example:// EX1_06.CPP
// Demonstrating variable scope
#include
using namespace std;
int main()
{ // Function scope starts here
int count1 = 10;
int count3 = 50;
cout << endl
<< "Value of outer count1 = " << count1
<< endl;
{ // New scope starts here...
int count1 = 20; // This hides the outer count1
int count2 = 30;
cout << "Value of inner count1 = " << count1
<< endl;
count1 += 3; // This affects the inner count1
count3 += count2;
} // ...and ends here
cout << "Value of outer count1 = " << count1
<< endl
<< "Value of outer count3 = " << count3
<< endl;
// cout << count2 << endl; // uncomment to get an error
return 0;
} // Function scope ends here

How It Works
The output from this example will be:
The first two statements declare and define two integer variables, count1 and count3, with initial values of 10 and 50 respectively. Both these variables exist from this point to the closing brace at the end of the program. The scope of these variables also extends to the closing brace at the end of main().
Remember that the lifetime and scope of a variable are two different things. It's important not to get these two ideas confused.
Following the variable definitions, the value of count1 is output to produce the first of the lines shown above.
There is then a second curly brace which starts a new block. Two variables, count1 and count2, are defined within this block, with values 20 and 30 respectively. The count1 declared here is different from the first count1. The first count1 still exists, but its name is masked by the second count1. Any use of the name count1 following the declaration within the inner block refers to the count1 declared within that block.
The variable name count1 has been duplicated here only to illustrate what happens. Although this code is legal, it isn't a good approach to programming in general. It's confusing, and it's very easy to hide variables defined in an outer scope accidentally.
The value shown in the second output line shows that within the inner block, we are using the count1 in the inner scope - that is, inside the innermost braces:cout << "Value of inner count1 = " << count1
<< endl;
Had we still been using the outer count1, then this would display the value 10. The variable count1 is then incremented by the statement: count1 += 3; // This affects the inner count1
The increment applies to the variable in the inner scope, since the outer one is still hidden. However, count3, which was defined in the outer scope, is incremented in the next statement without any problem:count3 += count2;
This shows that the variables which were declared at the beginning of the outer scope are accessible from within the inner scope. (Note that if count3 had been declared after the second of the inner pair of braces, then it would still be within the outer scope, but in that case count3 would not exist when the above statement is executed.)
After the brace ending the inner scope, count2 and the inner count1 cease to exist. The variables count1 and count3 are still there in the outer scope and the values displayed show that count3 was indeed incremented in the inner scope.
If you uncomment the line,// cout << count2 << endl; // uncomment to get an error
then the program will no longer compile correctly, because it attempts to output a non-existent variable. You will get an error message something like:
C:\Program Files\MyProjects\Ex1_06\Ex1_06.cpp(29): error C2065: 'count2': undeclared identifier
This is because count2 is out of scope at this point.
Positioning Variable Declarations
You have great flexibility in where you place the declarations for your variables. The most important aspect to consider is what scope the variables need to have. Beyond that, you should generally place a declaration close to where the variable is to be first used in a program. You should write your programs with a view to making them as easy as possible for another programmer to understand, and declaring a variable at its first point of use can be helpful in achieving that.
It is possible to place declarations for variables outside of all of the functions that make up a program. Let's look what effect that has on the variables concerned.
Global Variables
Variables that are declared outside of all blocks and classes (we will discuss classes later in the book) are called globals and have global scope (which is also called global namespace scope or file scope). This means that they are accessible throughout all the functions in the file, following the point at which they are declared. If you declare them at the very top of your program, they will be accessible from anywhere in the file.
Globals also have static storage duration by default. Global variables with static storage duration will exist from the start of execution of the program, until execution of the program ends. If you do not specify an initial value for a global variable, it will be initialized with 0 by default. Initialization of global variables takes place before the execution of main() begins, so they are always ready to be used within any code that is within the variable's scope.
The illustration below shows the contents of a source file, Example.cpp, and the arrows indicate the scope of each of the variables.
The variable value1 appearing at the beginning of the file is declared at global scope, as is value4, which appears after the function main(). The scope of each global variable extends from the point at which it is defined to the end of the file. Even though value4 exists when execution starts, it cannot be referred to in main() because main() is not within the variable's scope. For main() to use value4, you would need to move its declaration to the beginning of the file. Both value1 and value4 will be initialized with 0 by default, which is not the case for the automatic variables. Note that the local variable called value1 in function() hides the global variable of the same name.
Since global variables continue to exist for as long as the program is running, you might ask the question, 'Why not make all variables global and avoid this messing about with local variables that disappear?' This sounds very attractive at first, but as with the Sirens of mythology, there are serious side effects which completely outweigh any advantages you may gain.
Real programs are generally composed of a large number of statements, a significant number of functions and a great many variables. Declaring all variables at the global scope greatly magnifies the possibility of accidental erroneous modification of a variable, as well as making the job of naming them sensibly quite intractable. They will also occupy memory for the duration of program execution. By keeping variables local to a function or a block, you can be sure they have almost complete protection from external effects, they will only exist and occupy memory from the point at which they are defined to the end of the enclosing block, and the whole development process becomes much easier to manage.
If you take a look at ClassView for any of the examples that you have created so far, and extend the class tree for the project by clicking on the +, you will see an entry called Globals. If you extend this, you will see a list of everything in your program that has global scope. This will include all the global functions, as well as any global variables that you have declared.
Try It Out - The Scope Resolution Operator
As we have seen, a global variable can be hidden by a local variable with the same name. However, it's still possible to get at the global variable using the scope resolution operator, ::. We can demonstrate how this works with a revised version of the last example:// EX1_07.CPP
// Demonstrating variable scope
#include
using namespace std;
int count1 = 100; // Global version of count1
int main()
{ // Function scope starts here
int count1 = 10;
int count3 = 50;
cout << endl
<< "Value of outer count1 = " << count1
<< endl;
cout << "Value of global count1 = " << ::count1 // From outer block
<< endl;
{ // New scope starts here...
int count1 = 20; //This hides the outer count1
int count2 = 30;
cout << "Value of inner count1 = " << count1
<< endl;
cout << "Value of global count1 = " << ::count1 // From inner block
<< endl;
count1 += 3; // This affects the inner count1
count3 += count2;
} // ...and ends here.
cout << "Value of outer count1 = " << count1
<< endl
<< "Value of outer count3 = " << count3
<< endl;
//cout << count2 << endl; // uncomment to get an error

return 0;
} // Function scope ends here

How It Works
If you compile and run this example, you'll get the following output:
The shaded lines indicate the changes we have made to the previous example; we just need to discuss the effects of those. The declaration of count1 prior to the definition of the function main() is global, so in principle it is available anywhere through the function main(). This global variable is initialized with the value of 100: int count1 = 100; // Global version of count1
However, we have two other variables called count1, which are defined within main(), so throughout the program the global count1 is hidden by the local count1 variables. The first new output statement is:cout << "Value of global count1 = " << ::count1 // From outer block
<< endl;
This uses the scope resolution operator (::) to make it clear to the compiler that we want to reference the global variable count1, not the local one. You can see that this works from the value displayed in the output.
In the inner block, the global count1 is hidden behind two variables called count1: the inner count1 and the outer count1. We can see the global scope resolution operator doing its stuff within the inner block, as you can see from the output generated by the statement we have added there:cout << "Value of global count1 = " << ::count1 // From inner block
<< endl;
This outputs the value 100, as before - the long arm of the scope resolution operator used in this fashion always reaches a global variable.
We mentioned namespaces earlier in this chapter, when discussing the namespace std - we accessed the namespace std by employing the using directive. Alternatively, we can access a namespace by using the scope resolution operator - for example, we can write std::endl to access the end-of-line operator in the standard library. In the example above, we are using the scope resolution operator to search the global namespace for the variable count1. By not specifying a namespace in front of the operator, the compiler knows that must it search the global namespace for the name that follows it.
We'll be seeing a lot more of this operator when we get to talking about object-oriented programming, in which context it is used extensively. We'll also talk further about namespaces, including how to create your own, in Chapter 5.
Static Variables
It's conceivable that you might want to have a variable that's defined and accessible locally, but which also continues to exist after exiting the block in which it is declared. In other words, you need to declare a variable within a block scope, but to give it static storage duration. The static specifier provides you with the means of doing this, and the need for this will become more apparent when we come to deal with functions in Chapter 4.
In fact, a static variable will continue to exist for the life of a program even though it is declared within a block and only available from within that block (or its sub-blocks). It still has block scope, but it has static storage duration. To declare a static integer variable called count, you would write:static int count;
If you don't provide an initial value for a static variable when you declare it, then it will be initialized for you. The variable count declared here will be initialized with 0. The default initial value for a static variable is always 0, converted to the type applicable to the variable. Remember that this is not the case with automatic variables. If you don't initialize your automatic variables, they will contain junk values left over from the program that last used the memory they occupy.

Variable Types and Casting

Variable Types and Casting
Calculations in C++ can only be carried out between values of the same type. When you write an expression involving variables or constants of different types, for each operation to be performed the compiler has to convert the type of one of the operands to match that of the other. This conversion process is called casting. For example, if you want to add a double value to an integer, the integer value is first converted to double, after which the addition is carried out. Of course, the variable which contains the value to be cast is itself not changed. The compiler will store the converted value in a temporary memory location which will be discarded when the calculation is finished.
There are rules governing the selection of the operand to be converted in any operation. Any expression to be calculated can be broken down into a series of operations between two operands. For example, the expression 2*3-4+5 amounts to the series 2*3 resulting in 6, 6-4 resulting in 2, and finally 2+5 resulting in 7. Thus, the rules for casting operands where necessary only need to be defined in terms of decisions about pairs of operands. So, for any pair of operands of different types, the following rules are checked in the order that they are written. When one applies, that rule is used.
Rules for Casting Operands
If either operand is of type long double, the other is converted to long double.
If either operand is of type double, the other is converted to double.
If either operand is of type float, the other is converted to float.
Any operand of type char, signed char, unsigned char, short, or unsigned short is converted to type int.
An enumeration type is converted to the first of int, unsigned int, long, or unsigned long that accommodates the range of the enumerators.
If either operand is of type unsigned long, the other is converted to unsigned long.
If one operand is of type long and the other is of type unsigned int, then both operands are converted to type unsigned long.
If either operand is of type long, the other is converted to type long.
We could try these rules on a hypothetical expression to see how they work. Let's suppose that we have a sequence of variable declarations as follows:double value = 31.0;
int count = 16;
float many = 2.0f;
char num = 4;
Let's also suppose that we have the following rather arbitrary arithmetic statement:value = (value - count)*(count - num)/many + num/many;
We can now work out what casts the compiler will apply. The first operation is to calculate (value - count). Rule 1 doesn't apply but Rule 2 does, so the value of count is converted to double and the double result 15.0 is calculated. Next (count - num) must be evaluated, and here the first rule in sequence which applies is Rule 4, so num is converted from char to int, and the result 12 is produced as a value of type int. The next calculation is the product of the first two results, a double 15.0 and an int 12. Rule 2 applies here and the 12 is converted to 12.0 as double, and the double result 180.0 is produced. This result now has to be divided by many, so Rule 2 applies again and the value of many is converted to double before generating the double result 90.0. The expression num/many is calculated next, and here Rule 3 applies to produce the float value 2.0f after converting the type of num from char to float. Lastly, the double value 90.0 is added to the float value 2.0f for which Rule 2 applies, so after converting the 2.0f to 2.0 as double, the final result of 92.0 is stored in value as a double.
In spite of the last paragraph reading a bit like The Auctioneer's Song, I hope you get the general idea.
Casts in Assignment Statements
As we saw in example Ex1_04.cpp earlier in this chapter, you can cause an implicit cast by writing an expression on the right-hand side of an assignment that is of a different type to the variable on the left-hand side. This can cause values to be changed and information to be lost. For instance, if you assign a float or double value to an int or a long variable, the fractional part of the float or double will be lost and just the integer part will be stored. (You may lose even more information, if your floating point variable exceeds the range of values available for the integer type concerned.)
For example, after executing the following code fragment,int number = 0;
float decimal = 2.5f;
number = decimal;
the value of number will be 2. Note the f at the end of the constant 2.5. This indicates to the compiler that this constant is single precision floating point. Without the f, the default would have been double. Any constant containing a decimal point is floating point. If you don't want it to be double precision, you need to append the f. A capital F would do the job just as well.
Explicit Casts
With mixed expressions involving the basic types, your compiler automatically arranges casting where necessary, but you can also force a conversion from one type to another by using an explicit cast. To cast the value of an expression to a given type, you write the cast in the form:static_cast(expression)
The keyword static_cast reflects the fact that the cast is checked statically - that is, when your program is compiled. Later, when we get to deal with classes, we will meet dynamic casts, where the conversion is checked dynamically - that is, when the program is executing. The effect of the cast is to convert the value that results from evaluating expression to the type that you specify between the angled brackets. The expression can be anything from a single variable to a complex expression involving lots of nested parentheses.
Here's a specific example of the use of static_cast<>():double value1 = 10.5;
double value2 = 15.5;
int whole_number = static_cast(value1) + static_cast(value2);
The initializing value for the variable whole_number is the sum of the integral parts of value1 and value2, so they are each explicitly cast to type int. The variable whole_number will therefore have the initial value 25. The casts do not affect the values stored in value1 and value2, which will remain as 10.5 and 15.5 respectively. The values 10 and 15 produced by the casts are just stored temporarily for use in the calculation and then discarded. Although both casts cause a loss of information in the calculation, the compiler will always assume that you know what you are doing when you explicitly specify a cast.
Also, as we described in Ex1_04.cpp, when relating to assignments with different types, you can always make it clear that you know the cast is necessary by making it explicit:strips_per_roll = static_cast(rolllength/height); //Get number of strips in a roll
You can write an explicit cast for any standard type, but you should be conscious of the possibility of losing information. If you cast a float or double value to long, for example, you will lose the fractional part of the value converted, so if the value started out as less than 1.0, the result will be 0. If you cast double to float, you will lose accuracy because a float variable has only 7 digits precision, whereas double variables maintain 15. Even casting between integer types provides the potential for losing data, depending on the values involved. For example, the value of an integer of type long can exceed the maximum that you can store in a variable of type short, so casting from a long value to a short may lose information.
In general, you should avoid casting as far as possible. If you find that you need a lot of casts in your program, the overall design of your program may well be at fault. You need to look at the structure of the program and the ways in which you have chosen data types to see whether you can eliminate, or at least reduce, the number of casts in your program.
C++ provides three other types of explicit cast, although these are not so common as the static_cast<>(). These types are:
reinterpret_cast<>() - this handles casts between unrelated types, for example, an integer to a pointer
const_cast<>() - this removes the const qualifier
dynamic_cast<>() - this allows you to cast between pointers (and references) to polymorphic classes in an inheritance hierarchy. Don't worry about what these terms mean at the moment, we'll discuss them in more detail in chapter 8.
Old-Style Casts
Prior to the introduction of the new style casts into C++, an explicit cast of the result of an expression to another type was written as:(the_type_to_convert_to)expression
The result of expression is cast to the type between the parentheses. For example, the statement to calculate strips_per_roll in our previous example could be written:strips_per_roll = (int)(rolllength/height); //Get number of strips in a roll
Essentially, there are four different kinds of casts, and the old-style casting syntax covers them all. Because of this, code using the old-style casts is more error prone - it is not always clear what you intended, and you may not get the result you expected. Although you will still see the old style of casting used extensively (it's still part of the language), I strongly recommend that you stick to using only the new casts in your code.
The Bitwise Operators
The bitwise operators treat their operands as a series of individual bits rather than a numerical value. They only work with either integer variables or constants as operands, so only data types short, int, long and char can be used. They are useful in programming hardware devices, where the status of a device is often represented as a series of individual flags (that is, each bit of a byte may signify the status of a different aspect of the device), or for any situation where you might want to pack a set of on-off flags into a single variable. You will see them in action when we look at input/output in detail, where single bits are used to control various options in the way data is handled.
There are six bitwise operators:
& Bitwise AND Bitwise OR ^ Bitwise Exclusive OR
~ Bitwise NOT >> Shift right << Shift left
Let's take a look at how each of them works.
The Bitwise AND
The bitwise AND, &, is a binary operator that combines corresponding bits in its operands. If both corresponding bits are 1, the result is a 1 bit, and if either or both operand bits are 0, the result is a 0 bit.
The effect of a particular binary operator is often shown using what is called a truth table. This shows, for various possible combinations of operands, what the result is. The truth table for & is as follows:
Bitwise AND
0
1
0
0
0
1
0
1
For each row and column combination, the result of & combining the two is the entry at the intersection of the row and column. Let's see how this works in an example:char Letter1 = 'A', Letter2 = 'Z', Result = 0;
Result = Letter1 & Letter2;
We need to look at the bit patterns to see what happens. The letters 'A' and 'Z' correspond to hexadecimal values 0x41 and 0x5A respectively (see Appendix B for ASCII codes). The way in which the bitwise AND operates on these two values is shown below:
You can confirm this by looking at how corresponding bits combine with & in the truth table. After the assignment, Result will have the value 0x40, which corresponds to the character '@'.
Because the & produces zero if either bit is zero, we can use this operator to make sure that unwanted bits are zero in a variable. We achieve this by creating what is called a 'mask' and combining with the original variable using &. We create the mask by putting 1 where we want to keep a bit, and 0 where we want to set a bit to zero. The result will be 0s where the mask bit is 0, and the same value as the original bit in the variable where the mask is 1. Suppose we have a char variable, Letter, where, for the purposes of illustration, we want to eliminate the high order 4 bits, but keep the low order 4 bits. (Remember that a char variable occupies one byte, which is eight bits.) This is easily done by setting up a mask as 0x0F and combining it with the letter using & like this,Letter = Letter & 0x0F;
or, more concisely:Letter &= 0x0F;
If Letter started out as 0x41, it would end up as 0x01 as a result of either of these statements. This operation is clearly illustrated in the diagram below:
The 0 bits in the mask cause corresponding bits in Letter to be set to 0, and the 1 bits in the mask cause corresponding bits to be kept.
Similarly, you can use a mask of 0xF0 to keep the 4 high order bits, and zero the 4 low order bits. Therefore, this statement,Letter &= 0xF0;
will result in the value of Letter being changed from 0x41 to 0x40.
The Bitwise OR
The bitwise OR, , sometimes called the inclusive OR, combines corresponding bits such that the result is a 1 if either operand bit is a 1, and 0 if both operand bits are 0. The truth table for the bitwise OR is:
Bitwise OR
0
1
0
0
1
1
1
1
We can exercise this with an example of how we could set individual flags packed into a variable of type int. Let's suppose that we have a variable called style, of type short, which contains 16 individual 1-bit flags. Let's suppose further that we are interested in setting individual flags in the variable style. One way of doing this is by defining values that we can combine with the OR operator to set particular bits on. To use in setting the rightmost bit, we can define:short VREDRAW=0x01;
For use in setting the second-to-rightmost bit, we could define the variable hredraw as:short HREDRAW=0x02;
So we could set the rightmost two bits in the variable style to 1 with the statement:style = HREDRAWVREDRAW;
The effect of this statement is illustrated in the diagram below:
Because the OR operation results in 1 if either of two bits is a 1, ORing the two variables together produces a result with both bits set on.
A very common requirement is to be able to set flags in a variable without altering any of the others which may have been set elsewhere. We can do this quite easily with a statement such as:style = HREDRAWVREDRAW;
This statement will set the two rightmost bits of the variable style to 1, leaving the others at whatever they were before the execution of this statement.
The Bitwise Exclusive OR
The exclusive OR, ^, is so called because it operates similarly to the inclusive OR but produces 0 when both operand bits are 1. Therefore, its truth table is as follows:
Bitwise EOR
0
1
0
0
1
1
1
0
Using the same variable values that we used with the AND, we can look at the result of the following statement:result = letter1^letter2;
This operation can be represented as:
letter1 0100 0001
letter2 0101 1010
EORed together produce:
result 0001 1011
The variable result is set to 0x1B, or 27 in decimal notation.
The ^ operator has a rather surprising property. Suppose that we have two char variables, first with the value 'A', and last with the value 'Z', corresponding to binary values 0100 0001 and 0101 1010. If we write the statements,first ^= last; // Result first is 0001 1011
last ^= first; // Result last is 0100 0001
first ^= last; // Result first is 0101 1010
the result of these is that first and last have exchanged values without using any intermediate memory location. This works with any integer values.
The Bitwise NOT
The bitwise NOT, ~, takes a single operand for which it inverts the bits: 1 becomes 0, and 0 becomes 1. Thus, if we execute the statement,result = ~letter1;
and letter1 is 0100 0001, then the variable result will have the value 1011 1110, which is 0xBE, or 190 as a decimal value.
The Bitwise Shift Operators
These operators shift the value of an integer variable a specified number of bits to the left or right. The operator >> is for shifts to the right, while << is the operator for shifts to the left. Bits that 'fall off' either end of the variable are lost. The illustration below shows the effect of shifting the 2 byte variable left and right, with the initial value shown.
This one's on the production drive as 59_02_05.cdr
We declare and initialize a variable called number with the statement:unsigned short number = 16387U;
As we saw in the last chapter, we should write unsigned literals with a letter U or u appended to the number. We can shift the contents of this variable with the statement:number <<= 2; // Shift left two bit positions
The left operand of the shift operator is the value to be shifted, and the number of bit positions that the value is to be shifted is specified by the right operand. The illustration shows the effect of the operation. As you can see, shifting the value 16,387 two positions to the left produces the value 12. The rather drastic change in the value is the result of losing the high order bit.
We can also shift the value to the right. Let's reset the value of number to its initial value of 16,387. Then we can write:number >>= 2; // Shift right two bit positions
This shifts the value 16,387 two positions to the right, storing the value 4,096 in the variable number. Shifting right two bits is effectively dividing the value by 4 (without remainder). This is also shown in the illustration.
As long as bits are not lost, shifting n bits to the left is equivalent to multiplying the value by 2, n times. In other words, it is equivalent to multiplying by 2n. Similarly, shifting right n bits is equivalent to dividing by 2n. But beware: as we saw with the left shift of the variable number, if significant bits are lost, the result is nothing like what you would expect. However, this is no different from the multiply operation. If you multiplied the two-byte number by four you would get the same result, so shifting left and multiply are still equivalent. The problem of accuracy arises because the value of the result of the multiply is outside the range of a two-byte integer.
You might imagine that confusion could arise with the operators that we have been using for input and output. As far as the compiler is concerned, the meaning will always be clear from the context. If it isn't, the compiler will generate a message, but you need to be careful. For example, if you want to output the result of shifting a variable number left by two bits, you could write:cout << (number << 2);
Here, the parentheses are essential. Without them, the shift operator will be interpreted by the compiler as a stream operator, so you won't get the result that you intended.
In the main, the right shift operation is similar to the left shift. For example, if the variable number has the value 24, and we execute the statement,number >>= 2;
it will result in number having the value 6, effectively dividing by 4. However, the right shift operates in a special way with signed integer types that are negative (that is, the sign bit, which is the leftmost bit, is 1). In this case, the sign bit is propagated to the right. For example, let's declare and initialize a variable number, of type char, with the value -104 in decimal:char number = -104; // Binary representation is 1001 1000
Now we can shift it right 2 bits with the operation:number >>= 2; // Result 1110 0110
The decimal value of the result is -26, as the sign bit is repeated. With operations on unsigned integer types, of course, the sign bit is not repeated and zeros appear.
These shift operations can be faster than the regular multiply or divide operations on some computers - on an Intel 80486, for example, a multiply is slower than a shift left by at least a factor of 3. However, you should only use them in this way if you are sure you are not going to lose bits that you can ill afford to be without.

Calculating in C++

Calculating in C++
This is where we actually start doing something with the data that we enter. We are beginning the 'processing' part of a C++ program. Almost all of the computational aspects of C++ are fairly intuitive, so we should slice through this like a hot knife through butter.
The Assignment Statement
We have already seen examples of the assignment statement. A typical assignment statement would look like this:whole = part1 + part2 + part3;
The assignment statement enables you to calculate the value of an expression which appears on the right hand side of the equals sign (in this case the sum of part1, part2 and part3) and store the result in the variable specified on the left hand side (whole). In this statement, the whole is exactly the sum of its parts, and no more.
Note how the statement, as always, ends with a semicolon.
You can also write repeated assignments such as,A = B = 1;
where this is equivalent to assigning the value 1 to B, then assigning the value of B to A.
Understanding Lvalues
The simplest definition of an lvalue is something that has an address in memory. Usually this is something that can appear on the left hand side of an equals sign in an assignment, although this is not necessarily the case. Variables are lvalues, since they specify a place in memory. However, there are lvalues that can't appear on the left of an assignment, because their values have been defined as constant. We'll be looking at such variables a bit later in this chapter. The variables A and B appearing in the preceding paragraph are lvalues, whereas the expression A+B would not be, since its result doesn't determine an address in memory where a value might be stored.
Arithmetic Operations
The basic arithmetic operators we have at our disposal are addition, subtraction, multiplication and division, represented by the symbols +, -, * and / respectively. These operate generally as you would expect, with the exception of division, which has a slight aberration when working with integer variables or constants, as we'll see. You can write statements like this:netPay = hours * rate - deductions;
Here, the product of hours and rate will be calculated, then deductions subtracted from the value produced. The multiply and divide operators are executed before addition and subtraction. We will discuss the order of execution more fully later in this chapter. The overall result of the expression will be stored in the variable netPay.
The minus sign used in the last statement applies to two operands - it subtracts one from another. This is called a binary operation because two values are involved. The minus sign can also be used with one operand to change the sign of its value, in which case it is called a unary minus. You could write this:int A = 0;
int B = -5;
A = -B; // Changes the sign of the operand
Here, A will be assigned the value +5, because the unary minus changes the sign of the value of the operand B.
Note that an assignment is not the equivalent of the equations you saw in high school algebra. It specifies an action to be carried out rather than a statement of fact. The statement,A = A + 1;
means, 'add 1 to the current value stored in A and then store the result back in A'. As a normal algebraic statement it wouldn't make sense.
Try It Out - Exercising Basic Arithmetic
We can exercise basic arithmetic in C++ by calculating how many standard rolls of wallpaper are needed to paper a room. This is done with the following example:// EX1_04.CPP
// Calculating how many rolls of wallpaper are required for a room
#include
using namespace std;
int main()
{
double height = 0.0, width = 0.0, length = 0.0; // Room dimensions
double perimeter = 0.0; // Room perimeter
const double rollwidth = 21.0; // Standard roll width
const double rolllength = 12.*33.; // Standard roll length(33ft.)
int strips_per_roll = 0; // Number of strips in a roll
int strips_reqd = 0; // Number of strips needed
int nrolls = 0; // Total number of rolls
cout << endl // Start a new line
<< "Enter the height of the room in inches: ";
cin >> height;
cout << endl // Start a new line
<< "Now enter the length and width in inches: ";
cin >> length >> width;
strips_per_roll = rolllength/height; // Get number of strips in a roll
perimeter = 2.0*(length + width); // Calculate room perimeter
strips_reqd = perimeter/rollwidth; // Get total strips required
nrolls = strips_reqd/strips_per_roll; // Calculate number of rolls
cout << endl
<< "For your room you need " << nrolls << " rolls of wallpaper."
<< endl;
return 0;
}

How It Works
One thing needs to be clear at the outset. No responsibility is assumed for you running out of wallpaper as a result of using this program! As we shall see, all errors in the estimate of the number of rolls required are due to the way C++ works and to the wastage that inevitably occurs when you hang your own wallpaper - usually 50%+!
We can work through the statements in this example in sequence, picking out the interesting, novel, or even exciting features. The statements down to the start of the body of main() are familiar territory by now, so we will take those for granted.
A couple of general points worth noting are about the layout of the program. First, the statements in the body of main() are indented to make the extent of the body easier to see and, second, various groups of statements are separated by a blank line to indicate that they are functional groups. The compiler just ignores such whitespace, but indenting statements and leaving some lines blank is a fundamental technique in laying out program code in C++. You will see that this is applied universally to provide visual cues for various logical blocks in a program.
The const Modifier
We have a block of declarations for the variables used in the program right at the beginning of the body of main(). These statements are also fairly familiar, but there are two which contain some new features:const double rollwidth =21.0; // Standard roll width
const double rolllength = 12.*33.; // Standard roll length(33ft.)
They both start out with a new keyword: const. This is a type modifier which indicates that the variables are not just of type double, but are also constants. Because we effectively tell the compiler that these are constants, the compiler will check for any statements which attempt to change their values and, if it finds any, it will generate an error message. This is relatively easy since a variable declared as const cannot legally be placed on the left of an assignment operation.
You could check this out by adding, anywhere after the declaration of rollwidth, a statement such as:rollwidth = 0;
You will find the program no longer compiles.
It can be very useful defining constants by means of const variable types, particularly when you use the same constant several times in a program. For one thing, if you need to change it, you will only need to change its definition at the beginning to ensure that the change automatically appears throughout. We'll see this technique used quite often.
Constant Expressions
The const variable rolllength is also initialized with an arithmetic expression (12.*33.). Being able to use constant expressions to initialize variables saves having to work out the value yourself, and can also be more meaningful, as 33 feet times 12 inches is much clearer than simply writing 396. The compiler will generally evaluate constant expressions accurately, whereas if you do it yourself, depending on the complexity of the expression and your ability to number-crunch, there is a finite probability that it may be wrong.
You can use any expression that can be calculated as a constant at compile time, including const objects that you have already defined. So, for instance, if it was useful in the program to do so, we could declare the area of a standard roll of wallpaper as:const double rollarea = rollwidth*rolllength;
Obviously, this statement would need to be placed after the declarations for the two const variables used in the initialization of rollarea.
Program Input
The next four statements in the program handle input:cout << endl // Start a new line
<< "Enter the height of the room in inches: ";
cin >> height;
cout << endl // Start a new line
<< "Now enter the length and width in inches: ";
cin >> length >> width;
Here we have used cout to prompt for the input required and then read the input from the keyboard using cin. We first obtain the room height and then read the length and width successively. In a practical program, we would need to check for errors, and possibly make sure that the values that are read are sensible, but we don't have enough knowledge to do that yet!
Calculating the Result
We have four statements involved in calculating the number of standard rolls of wallpaper required for the size of room given:strips_per_roll = rolllength/height; // Get number of strips in a roll
perimeter = 2.0*(length + width); // Calculate room perimeter
strips_reqd = perimeter/rollwidth; // Get total strips required
nrolls = strips_reqd/strips_per_roll; // Calculate number of rolls
The first statement calculates the number of strips of paper with a length corresponding to the height of the room that we can get from a standard roll, by dividing one into the other. So, if the room is 8 feet high, we divide 96 into 396, which would produce the floating point result 4.125. There is a subtlety here, however. The variable where we store the result, strips_per_roll, was declared as int, so it can only store integer values. Consequently, any floating point value to be stored as an integer is rounded down to the nearest integer, 4 in our case, and this value is stored. This is actually the result that you want here since, although they may fit under a window or over a door, fractions of a strip are best ignored when estimating.
The conversion of a value from one type to another is called casting. This particular example is called an implicit cast, because the code doesn't explicitly state that a cast is needed, and the compiler has to work it out for itself. You should beware when using implicit casts. The compiler does not supply a warning that an implicit cast is being made, and if you are assigning a value of one type to a variable of a type with a lesser range of values, then there is a danger that you will lose information. If there are implicit casts in your program which you don't know about, then they will almost certainly form bugs which are difficult to locate.
Where such an assignment is unavoidable, you can specify the conversion explicitly to demonstrate that it is no accident and that you really meant to do it. We do this by making an explicit cast of the value on the right of the assignment to int, so the statement would become:strips_per_roll = static_cast(rolllength/height); //Get number of strips in a roll
The addition of static_cast(), with the parentheses around the expression on the right, tells the compiler explicitly to convert the value of the expression to int. Although this means that we still lose the fractional part of the value, the compiler assumes that we know what we are doing and does not issue a warning. We'll see more about static_cast<>(), and other types of explicit casting, later in this chapter.
Note how we calculate the perimeter of the room in the next statement. In order to multiply the sum of the length and the width by two, we enclose the sum of the two variables between parentheses. This ensures that the addition is performed first and the result is then multiplied by 2.0 to give us the correct value for the perimeter. We can use parentheses to make sure that a calculation is carried out in the order we require, since expressions in parentheses are always evaluated first. Where there are nested parentheses, the expressions within the parentheses are evaluated in sequence, from the innermost to the outermost.
The third statement, calculating how many strips of paper are required to cover the room, uses the same effect that we observed in the first statement: the result is rounded down to the nearest integer, because it is to be stored in the integer variable, strips_reqd. This is not what we need in practice. It would be best to round up for estimating, but we don't have enough knowledge of C++ to do this yet. Once you have read the next chapter, you can come back and fix it!
The last arithmetic statement calculates the number of rolls required by dividing the number of strips required (integer) by the number of strips in a roll (also integer). Because we are dividing one integer by another, the result has to be integer, so any remainder is ignored. This would still be the case if the variable nrolls were floating point. The resulting integer value would be converted to floating point form before it was stored in nrolls. The result that we obtain is essentially the same as if we had produced a floating point result and rounded down to the nearest integer. Again, this is not what we want, so if you want to use this, you will need to fix it.
Displaying the Result
The result of the calculation is displayed by the following statement:cout << endl
<< "For your room you need " << nrolls << " rolls of wallpaper."
<< endl;
This is a single output statement spread over three lines. It first outputs a newline character, then the text string "For your room you need ". This is followed by the value of the variable, nrolls, and finally the text string, " rolls of wallpaper.". As you can see, output statements are very easy in C++.
Finally, the program ends when this statement is executed: return 0;
The value zero here is a return value which, in this case, will be returned to the operating system.
Calculating a Remainder
We have seen in the last example that dividing one integer value by another produces an integer result that ignores any remainder, so if you take 11 divided by 4, then you get the result 2. Since the remainder after division can be of great interest, particularly when you are dividing cookies amongst children, for example, C++ provides a special operator, %, for this. So we can write the statements,int residue = 0, cookies = 19, children = 5;
residue = cookies % children;
and the variable residue will end up with the value 4 - the number left after dividing 19 by 5. To calculate how many each of them received, you just need to use division, as in the statement:each = cookies / children;
This statements says that the result of the division cookies/children, 3, will be stored in the variable each.
Modifying a Variable
It's often necessary to modify the existing value of a variable, such as incrementing it or doubling it. We could increment a variable called count using the statement:count = count + 5;
This simply adds 5 to the current value stored in count, and stores the result back in count, so if count started out at 10, it would end up as 15. You have an alternative, shorthand way of writing the same thing in C++:count += 5;
This says, 'Take the value in count, add 5 to it and store the result back in count'. We can also use other operators with this notation. For example, the statement,count *= 5;
has the effect of multiplying the current value of count by 5 and storing the result back in count. In general, we can write statements of the form,lhs op= rhs;
where op is any of the following operators: + - * / %
<< >> & ^
The first five of these we have already met, and the remainder, which are shift and logical operators, we will see later in this chapter. lhs stands for any legal expression for the left-hand side of the statement, and is usually (but not necessarily) a variable name. rhs stands for any legal expression on the right-hand side of the statement.
The general form of the statement is equivalent to this:lhs = lhs op (rhs);
This means that we can write statements such as,A /= B + C;
which will be identical in effect to,A = A/(B + C);

The Increment and Decrement Operators
We will now take a brief look at some unusual arithmetic operators called the increment and decrement operators, as we will find them to be quite an asset once we get further into applying C++ in earnest. These are unary operators, which are used to increment or decrement a variable. For example, assuming the variable count is of type int, the following three statements all have exactly the same effect:count = count + 1;
count += 1;
++count;
They each increment the variable count by 1. The last form, using the increment operator, is clearly the most concise. If this action is contained within another expression then the action of the operator is to first increment the value of the variable, and then use the incremented value in the expression. For example, if count has the value 5, and the variable total is of type int, then the statement,total = ++count + 6;
will result in count being incremented to 6, while total is then assigned the value 12.
So far, we have written the increment operator, ++, in front of the variable to which it applies. This is called the prefix form. The increment operator also has a postfix form, where the operator is written after the variable to which it applies; the effect of this is slightly different. The variable to which the operator applies is only incremented after its value has been used in context. For example, let's reset count to the value 5, and rewrite the previous example as:total = count++ + 6;
Here, total is assigned the value 11, since the initial value of count is used to evaluate the expression before it is incremented by 1. The statement above is equivalent to the two statements:total = count + 6;
++count;
The clustering of '+' signs, in the example of the postfix form above, is likely to lead to confusion. Generally, it isn't a good idea to write the increment operator in the way that we have here. It would be clearer to write:total = 6 + count++;
Where we have an expression such as a++ + b, or even a+++b, it becomes less obvious what is meant or what the compiler will do. They are actually the same, but in the second case you might really have meant a + ++b, which is different - it evaluates to one more than the other two expressions.
Exactly the same rules that we have discussed in relation to the increment operator also apply to the decrement operator, --. For example, if count has the initial value 5, then the statement,total = --count + 6;
results in total having the value 10 assigned, whereas,total = 6 + count--;
sets the value of total to 11. Both operators are usually applied to integers, particularly in the context of loops, as we shall see in the next chapter. We shall also see in later chapters that they can be applied to other data types in C++.
Try It Out - The Comma Operator
The comma operator allows you to specify several expressions where normally only one might occur. This is best understood by looking at an example of how it is used:// EX1_05.CPP
// Exercising the comma operator
#include
using namespace std;
int main()
{
long num1 = 0, num2 = 0, num3 = 0, num4 = 0;
num4 = (num1 = 10, num2 = 20, num3 = 30);
cout << endl
<< "The value of a series of expressions "
<< "is the value of the right most: "
<< num4;
cout << endl;
return 0;
}

How It Works
If you compile and run this program you will get this output:
This is fairly self-explanatory. The variable num4 receives the value of the last of the series of three assignments, the value of an assignment being the value assigned to the left-hand side. The parentheses in the assignment for num4 are essential. You could try executing this without them to see the effect. Without the parentheses, the first expression separated by commas in the series will become:num4 = num1 = 10
So, num4 will have the value 10.
Of course, the expressions separated by the comma operator don't have to be assignments. We could equally well write the following:long num1 = 1, num2 = 10, num3 = 100, num4 = 0;
num4 = (++num1, ++num2, ++num3);
The effect of this assignment would be to increment the variables num1, num2 and num3 by 1, and to set num4 to the value of the last expression which will be 101.
This example is aimed at illustrating the effect of the comma operator, and is not an example of how to write good code. As you can see, writing an assignment statement in this fashion can be very misleading.
The Sequence of Calculation
So far, we haven't talked about how we arrive at the sequence of calculations involved in evaluating an expression. It generally corresponds to what you will have learnt at school when dealing with basic arithmetic operators, but there are many other operators in C++. To understand what happens with these, we need to look at the mechanism used in C++ to determine this sequence. It's referred to as operator precedence.
Operator Precedence
Operator precedence orders the operators in a priority sequence. In any expression, operators with the highest precedence are always executed first, followed by operators with the next highest precedence, and so on, down to those with the lowest precedence of all. A list of all the C++ operators in order of their precedence can be found in the online help in Visual C++ Documentation \ Reference \ C/C++ Language and C++ Libraries \ C++ Language Reference \ Lexical Conventions \ C++ Operators.
If there are no parentheses in an expression, operators of equal precedence are executed in a sequence determined by their associativity. Thus, if the associativity is 'left to right', the left-most operator in an expression is executed first, progressing through the expression to the right-most.
Note that where an operator has a unary (working with one operand) and a binary (working with two operands) form, the unary form is always of a higher precedence and is, therefore, executed first.
You can always override the precedence of operators by using parentheses. Since there are so many operators in C++, it's sometimes hard to be sure what takes precedence over what. It is a good idea to insert parentheses to make sure. A further plus is that parentheses often make the code much easier to read.

Basic Input/Output Operations

Basic Input/Output Operations
C++ input/output revolves around the notion of a data stream, where we can insert data into an output stream or extract data from an input stream. We have already seen that the standard output stream to the screen is referred to as cout. The input stream from the keyboard is referred to as cin.
Input from the Keyboard
We obtain input from the keyboard through the stream cin, using the extractor operator for a stream, >>. To read two integer values from the keyboard into integer variables num1 and num2, you can write this:cin >> num1 >> num2;
The operator 'points' in the direction that data flows - in this case, from cin to each of the two variables in turn. Any leading whitespace is skipped and the first integer value you key in is read into num1. This is because the input statement executes from left to right. Whitespace following num1 is ignored and the second integer value that you enter is read into num2. There has to be some whitespace between successive values though, so that they can be differentiated. The stream input operation ends when you press the Enter key and execution then continues with the next statement. Of course, errors can arise if you key in the wrong data, but we will assume that you always get it right!
Floating point values are read from the keyboard in exactly the same way as integers and, of course, we can mix the two. The stream input and operations automatically deal with variables and data of any of the basic types. For example, look at the statements,int num1 = 0, num2 = 0;
double factor = 0.0;
cin >> num1 >> factor >> num2;
The last line will read an integer into num1, then a floating point value into factor and, finally, an integer into num2.
Try It Out - Output to the Display
Writing information to the display operates in a complementary fashion to input. The stream is called cout and we use the insertion operator, <<. This also 'points' in the direction of data movement. We have already used this operator to output a text string between quotes. We can demonstrate the process of outputting the value of a variable with a simple program. We'll assume that you've got the hang of creating a new project and a new source file, adding the source file to the project and building it into an executable. Here's the code:// EX1_02.CPP
// Exercising output
#include
using namespace std;
int main()
{
int num1 = 1234, num2 = 5678;
cout << endl; //Start on a new line
cout << num1 << num2; //Output two values
cout << endl; //End on a new line
return 0; //Exit program
}

How It Works
The first statement in the body of main() declares and initializes two integer variables, num1 and num2. This is followed by two output statements, the first of which moves the screen cursor position to a new line. Because output statements execute from left to right, the second output statement displays the value of num1 followed by the value of num2.
When you compile and execute this, you will get the output:
This is correct, but not exactly helpful. We really need the two output values to be separated by at least one space. The default for stream output is to just output the digits in the output value, which doesn't provide for spacing different values out nicely, so they can be differentiated. As it is, we have no way to tell where the first number ends and the second number begins.
Try It Out - Manipulators
We can fix this quite easily, though, just by outputting a space between the two values. We can do this by replacing the following line in our original program:cout << num1 << num2; //Output two values
with the statement:cout << num1 << ' ' << num2; //Output two values
Of course, if we had several rows of output that we wanted to align in columns, we would need some extra capability, as we do not know how many digits there will be in each value. We can take care of this situation by using what is called a manipulator. A manipulator modifies the way in which data output to (or input from) a stream is handled.
Manipulators are defined in the header file iomanip, so we need to add a #include statement for it. The manipulator that we will use is setw(n), which will output the following value right-justified in a field n spaces wide, so setw(6) puts the output in a field with a width of six spaces. To get something more like the output we want, we can change our program to the following:// EX1_03.CPP
// Exercising output
#include
#include
using namespace std;
int main()
{
int num1 = 1234, num2 = 5678;
cout << endl; //Start on a new line
cout << setw(6) << num1 << setw(6) << num2; //Output two values
cout << endl; //Start on a new line
return 0; //Exit program
}
Note that the highlighted lines indicate the code that has changed compared to the previous example.
How It Works
The only changes from the last example are the addition of the #include statement for the file iomanip, and the insertion of the setw() manipulator in the output stream preceding each value, to output the values in a field six characters wide. Now we get nice neat output where we can actually separate the two values:
Note that the setw() manipulator only works for the single output value immediately following it. We have to insert it into the stream immediately preceding each value that we want to output within a given field width. If we put only one setw(), it would apply to the first value to be output after it was inserted. Any following value would be output in the default manner. You could try this out by deleting the second setw(6) and its insertion operator in the above example.
Escape Sequences
When we write a character string between quotes, we can include special characters called escape sequences. They are called escape sequences because they allow characters to be included in a string that otherwise could not be represented. An escape sequence starts with a backslash character, \. For example, a tab character is written as \t, so these two output statements,cout << endl << "This is output.";
cout << endl << "\tThis is output after a tab.";
will produce these lines:
This is output.
This is output after a tab.
In fact, instead of using endl, we could include the escape sequence for the newline character, \n, in each string, so we could rewrite the statements above as follows:cout << "\nThis is output.";
cout << "\n\tThis is output after a tab.";
Here are some escape sequences which may be particularly useful:
Escape sequence
What it does
\a
sounds a beep
\n
newline
\'
single quote
\\
backslash
\b
backspace
\t
tab
\"
double quote
Obviously, if you want to be able to include a backslash or a double quote as a character to be output in a string between quotes, you must use the escape sequences to represent them. Otherwise, the backslash would be interpreted as another escape sequence and a double quote would indicate the end of the character string.
You can also use characters specified by escape sequences in the initialization of char variables. For example:char Tab = '\t'; // Initialize with tab character
That gives us enough of a toehold in input/output. We will collect a few more bits and pieces as and when we need them.

Data Types in C++

Data Types in C++
The sort of information that a variable can hold is determined by its data type. All data and variables in your program must be of some defined type. C++ provides you with a range of standard data types, specified by particular keywords. We have already seen the keyword int for defining integer variables. As part of the object-oriented aspects of the language, you can also create your own data types, as we shall see later. For the moment, let's take a look at the elementary numerical data types that C++ provides.
Integer Variables
As we have said, integer variables are variables that can only have values that are whole numbers. The number of players in a football team is an integer, at least at the beginning of the game. We already know that you can declare integer variables using the keyword int. These are variables which occupy 4 bytes in memory and can take both positive and negative values.
The upper and lower limits for the values of a variable of type int correspond to the maximum and minimum signed binary numbers which can be represented by 32 bits (4 bytes). The upper limit for a variable of type int is 231-1, and the lower limit is -231.
In Visual C++, the keyword short also defines an integer variable, this time occupying two bytes. The keyword short is equivalent to short int.
C++ also provides another integer type, long, which can also be written as long int. In this case, we can write the statement,long bigNumber = 1000000L, largeValue = 0L;
where we declare the variables bigNumber and largeValue with initial values 1000000 and 0 respectively. The letter L appended to the end of the values specifies that they are long integers. You can also use the small letter l for the same purpose, but it has the disadvantage that it is easily confused with the numeral 1.
We don't include commas when writing large numeric values in a program.
Integer variables declared as long occupy 4 bytes and since this is the same as variables declared as int using Visual C++ 6.0, they have the same range of values.
With other C++ compilers, long and long int may not be the same as int, so if you expect your programs to be compiled in other environments, don't assume that long and int are equivalent. For truly portable code, you should not even assume that an int is 4 bytes (for example, under older 16-bit versions of Visual C++ an int was 2 bytes).
The char Data Type
The char data type serves a dual purpose. It specifies a one-byte variable that you can use to store integers, or to store a single ASCII character, which is the American Standard Code for Information Interchange. We can declare a char variable with this statement:char letter = 'A';
This declares the variable letter and initializes it with the constant 'A'. Note that we specify a value which is a single character between single quotes, rather than the double quotes which we used previously for defining a string of characters to be displayed. A string of characters is a series of values of type char, which are grouped together into a single entity called an array. We will discuss arrays and how strings are handled in C++ in Chapter 3.
Because the character 'A' is represented in ASCII by the decimal value 65, we could have written this:char letter = 65; // Equivalent to A
to produce the same result as the previous statement. The range of integers that can be stored in a variable of type char is from -128 to 127.
We can also use hexadecimal constants to initialize char variables (and other integer types). A hexadecimal number is written using the standard representation for hexadecimal digits: 0 to 9, and A to F (or a to f) for digits with values from 10 to 15. It's also preceded by 0x (or 0X) to distinguish it from a decimal value. Thus, to get exactly the same result again, we could rewrite the last statement as follows:char letter = 0x41; // Equivalent to A
Don't write decimal integer values with a leading zero. The compiler will interpret such values as octal (base 8), so a value written as 065 will be equivalent to 53 in normal decimal notation.
Integer Type Modifiers
Variables of the integral types char, int, short or long, which we have just discussed, contain signed values by default. That is, they can store both positive and negative values. This is because the default type modifier for these types is the modifier signed. So, wherever we wrote char, int, or long, we could have written signed char, signed int, or signed long respectively.
If you are sure that you don't need to store negative values in a variable (for example, if you were recording the number of miles you drive in a week), then you can specify a variable as unsigned:unsigned long mileage = 0UL;
Here, the minimum value that can be stored in the variable mileage is zero, and the maximum value is 4,294,967,295 (that's 232-1). Compare this to the range of -2,147,483,648 to 2,147,483,647 for a signed long. The bit which is used in a signed variable to determine the sign, is used in an unsigned variable as part of the numeric value instead. Consequently, an unsigned variable has a larger range of positive values, but it can't take a negative value. Note how a U (or u) is appended to unsigned constants. In the above example, we also have appended L to indicate that the constant is long. You can use either upper or lower case for U and L and the sequence is unimportant, but it's a good idea to adopt a consistent way of specifying such values.
Of course, both signed and unsigned are keywords, so you can't use them as variable names.
Floating Point Variables
Values which aren't integral are stored as floating point numbers. A floating point number can be expressed as a decimal value such as 112.5, or with an exponent such as 1.125E2 where the decimal part is multiplied by the power of 10 specified after the E (for Exponent). Our example is, therefore, 1.125×102, which is 112.5.
A floating point constant must contain a decimal point, or an exponent, or both. If you write neither, you have an integer.
You can specify a floating point variable using the keyword double, as in this statement:double in_to_mm = 25.4;
A double variable occupies 8 bytes of memory and stores values accurate to 15 decimal digits. The range of values stored is much wider than that indicated by the 15 digits accuracy, being from 1.7×10-308 to 1.7×10308, and can be either positive or negative. Note that you can't get exactly zero with a floating point number, which can occasionally cause some strange errors in calculations.
If you don't need 15 digits precision, and you don't need the massive range of values provided by double variables, you can opt to use the keyword float to declare floating point variables occupying 4 bytes. For example, the statement,float pi = 3.14159f;
defines a variable pi with the initial value 3.14159. The f at the end of the constant specifies it to be a float type. Without the f, the constant would have been of type double. Variables declared as float are of 7 decimal digits precision and can have values from 3.4×10-38 to 3.4×1038, positive and negative.
You can find a complete summary of the various data types in the MSDN online documentation, provided with Visual C++ 6.0.
Logical Variables
Logical variables can only have two values: a value called true or a value called false. The type for a logical variable is bool, named after George Boole, who developed Boolean algebra. Variables of type bool are used to store the results of tests which can be either true or false, such as whether one value is equal to another. You can declare a variable of type bool with the statement:bool testResult;
Of course, you can also initialize them when you declare them:bool colorIsRed = true;
You will find that the values true and false are used quite extensively with variables of numeric type, and particularly of type int. This is a hangover from the time before variables of type bool were implemented in C++. The symbols TRUE and FALSE commonly represented the integers 1 and 0 respectively, which generally worked in the same way as the bool values true and false. Note that TRUE and FALSE are not keywords in C++, and they are not legal bool values.
Variables with Specific Sets of Values
You will sometimes be faced with the need for variables that have a limited set of possible values which can be usefully referred to by labels - the days of the week, for example, or months of the year. There is a specific facility in C++ to handle this situation, called an enumeration. Let's take one of the examples we have just mentioned - a variable that can assume values corresponding to days of the week. We can define this as follows:enum Week {Mon, Tues, Wed, Thurs, Fri, Sat, Sun} this_week;
This declares an enumeration type called Week and the variable this_week, which is an instance of the enumeration type Week that can only assume the values specified between the braces. If you try to assign anything other than one of the set of values specified to this_week, it will cause an error. The symbolic names listed between the braces are known as enumerators. In fact, each of the names of the days will be automatically defined as representing a fixed integer value. The first name in the list, Mon, will have the value 0, Tues will be 1, and so on. By default, each successive enumerator is one larger than the value of the previous one. If you would prefer the implicit numbering to start at a value other than zero, you can just writeenum Week {Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun} this_week;
and they will be equivalent to 1 through 7. The enumerators don't even need to have unique values. You could define Mon and Tues as both having the value 1 for example, with the statement:enum Week {Mon = 1, Tues = 1, Wed, Thurs, Fri, Sat, Sun} this_week;
As it's the same as an int, the variable this_week will occupy four bytes, as will all variables which are of an enumeration type.
Having defined the form of an enumeration, you can define another variable thus:enum Week next_week;
This defines a variable next_week as an enumeration that can assume the values previously specified. You can also omit the keyword enum in declaring a variable so, instead of the previous statement, you could write:Week next_week;
If you wish, you can assign specific values to all the enumerators. For example, we could define this enumeration:enum Punctuation {Comma=',', Exclamation='!', Question='?'} things;
Here we have defined the possible values for the variable things as the numerical equivalents of the appropriate symbols. The ASCII codes for these symbols are 44, 33 and 63 respectively in decimal. As you can see, the values assigned don't have to be in ascending order. If you don't specify all the values explicitly, values continue to be assigned incrementing by 1 from the last specified value, as in our second Week example.
You can omit the enumeration type if you don't need to define other variables of this type later. For example:enum {Mon, Tues, Wed, Thurs, Fri, Sat, Sun} thisWeek, nextWeek, lastWeek;
Here we have three variables declared that can assume values from Mon to Sun. Since the enumeration type is not specified, we cannot refer to it. Note that you cannot define other variables for this enumeration at all, since you would not be permitted to repeat the definition. Doing so would imply that you were redefining values for Mon to Sun, and this isn't allowed.
Defining Your Own Data Types
The typedef keyword enables you to define your own data type specifier. Using typedef, you could define the type name BigOnes as equivalent to the standard long int type with the declaration:typedef long int BigOnes; // Defining BigOnes as a type name
This defines BigOnes as an alternative type specifier for long int, so you could declare a variable mynum as long int with the declaration:BigOnes mynum = 0L; // Define a long int variable
There's no difference between this declaration and the one using the built-in type name. You could equally well use:long int mynum = 0L; // Define a long int variable
for exactly the same result. In fact, if you define your own type name such as BigOnes, you can use both type specifiers within the same program for declaring different variables that will end up as having the same type.
Since typedef only defines a synonym for an existing type, it may appear to be a bit superficial. We will see later that it can fulfill a very useful role in enabling us to simplify more complex declarations than we have met so far. We will also see later (in chapter 6) that classes provide us with a means of defining completely new data types.

Defining Variables

Defining Variables
Now that we are beyond our first program, we are going to want to manipulate some meaningful information and get some answers. An essential element in this process is having a piece of memory that we can call our own, that we can refer to using a meaningful name and where we can store an item of data. Each individual piece of memory so specified is called a variable.
Each variable will store a particular kind of data, which is fixed when we define the variable in our program. One variable might store whole numbers (that is, integers), in which case it couldn't be used to store numbers with fractional values. The value that each variable contains at any point is determined by the instructions in our program and, of course, its value will usually change many times as the program calculation progresses.
Let's look first at the rules for naming a variable when we introduce it into a program.
Naming Variables
The name we give to a variable is called an identifier, or more conveniently, a variable name. Variable names can include the letters A-z (upper or lower case), the digits 0-9 and the underscore character. All other characters are illegal. Variable names must also begin with either a letter or an underscore. Names are usually chosen to indicate the kind of information to be stored.
In Visual C++, variable names can be up to 247 characters long, which gives you a reasonable amount of flexibility. In fact, as well as variables, there are quite a few other things that have names in C++. We shall see they too can have names of up to 247 characters, with the same definition rules as a variable name. Using names of the maximum length can make your programs a little difficult to read and, unless you have amazing keyboard skills, they are the very devil to type in. A more serious consideration is that not all compilers support such long names. If you anticipate compiling your code in other environments, names with up to 31 characters are usually adequate and will not cause problems in most instances.
Although you can use variable names that begin with an underscore, for example _this and _that, this is best avoided, because there are potential clashes with standard system variables which have the same form. You should also avoid using names starting with a double underscore for the same reason.
Examples of good variable names are:
Price
discount
pShape
Value_
COUNT
8_Ball, 7Up, and 6_pack are not legal. Neither is Hash! or Mary-Ann. This last example is a common mistake, although Mary_Ann would be quite acceptable. Of course, Mary Ann would not be, because blanks are not allowed in variable names. Note that the variable names republican and Republican are quite different, as upper- and lower-case letters are differentiated.
Keywords in C++
There are reserved words in C++, also called keywords, which have special significance within the language. They will be highlighted with a particular color by the Visual C++ editor as you enter your program. If the keywords you type do not appear highlighted, then the keyword has been entered incorrectly.
Remember that keywords, like the rest of the C++ language, are case-sensitive.
For example, the program that you entered earlier in the chapter contained the keywords int and return. You will see many more as you progress through the book. You must ensure that the names you choose for entities in your program, such as variables, are not the same as any of the keywords in C++. You can find a complete list of the C++ keywords in the online help, if you look under Visual C++ Documentation \ Reference \ C/C++ Language and C++ Libraries \ C++ Language Reference \ Lexical Conventions \ C++ Keywords.
Declaring Variables
A variable declaration is a program statement which specifies the name of a variable and the sort of data that it can store. For example, the statement,int value;
declares a variable with the name value that can store integers. The type of data that can be stored in the variable value is specified by the keyword int. Because int is a keyword, you can't use int as a name for one of your variables.
Note that a declaration always ends with a semicolon.
A single declaration can specify the names of several variables but, as we have said, it is generally better to declare variables in individual statements, one per line. We will deviate from this from time to time, but only in the interests of keeping the code reasonably compact.
A variable name alone can't store anything, so it's not much use on its own. In order to store data (for example, the value of an integer), we need to assign a piece of the computer's memory to the variable. This process is called variable definition.
In C++, a variable declaration is also a definition (except in a few special cases, which we shall come across during the book). In the course of a single statement, we introduce the variable name, and also tie it to an appropriately-sized piece of memory. So, the statement int value;
is both a declaration and a definition. We use the variable name value that we declared, to access the piece of the computer's memory that we defined.
We use the term declaration when we introduce a name to our program, with information on what the name will be used for. The term definition refers to the allotment of computer memory to the name. In the case of variables, we can declare and define in a single statement, as in the line above.
You must declare a variable at some point between the beginning of your program and when the variable is used for the first time. In C++, it is good practice to declare variables close to their first point of use.
Initial Values for Variables
When you declare a variable, you can also assign an initial value to it. A variable declaration that assigns an initial value to a variable is called an initialization. To initialize a variable when you declare it, you just need to write an equals sign followed by the initializing value after the variable name. We can write the following statements to give each of the variables an initial value:int value = 0;
int count = 10;
int number = 5;
In this case, value will have the value 0, count will have the value 10 and number will have the value 5. These three statements are each declarations, definitions and initializations.
There is another way of writing the initial value for a variable in C++ called functional notation. Instead of an equals sign and the value, you can simply write the value in parentheses following the variable name. So we could rewrite the previous declarations as:int value(0);
int count(10);
int number(5);
If you don't supply an initial value for a variable, then it will usually contain whatever garbage was left in the memory location it occupies by the previous program you ran (there is an exception to this which we shall see later). Wherever possible, you should initialize your variables when you declare them. If your variables start out with known values, it makes it easier to work out what is happening when things go wrong. And if there's one thing you can be sure of, it's that things will go wrong.

The Structure of a C++ Program

Programs which will run as console applications under Visual C++ are text-based MS-DOS programs. All the examples that we'll write to understand how C++ works will be MS-DOS programs, so let's look at how such programs are structured.
A program in C++ consists of one or more functions. Every C++ program in the DOS environment contains the function main() and all C++ programs of any size consist of several functions. A function is simply a self-contained block of code with a unique name which is invoked by using the name of the function.
A typical DOS program might be structured as shown in the figure:
The figure above illustrates that execution of the program shown starts at the beginning of the function main(). From main(), execution transfers to a function input_names(), which returns execution to the position immediately following the point where it was called in main(). The function sort_names() is then called from main() and, once control returns to main(), the final function output_names() is called. Eventually, once output has been completed, execution returns once again to main() and the program ends.
Of course, different programs under DOS may have radically different functional structures, but they all start execution at the beginning of main(). The principal advantage of having a program broken up into functions is that you can write and test each piece separately. There is a further advantage in that functions written to perform a particular task can be re-used in other programs. The libraries that come with C++ provide a lot of standard functions that you can use in your programs. They can save you a great deal of work.
We'll see more about creating and using functions in Chapter 4.
Try It Out - A Simple Program
Let's look at a simple example to understand the elements of a program a little better. Start by creating a new project from the range of alternatives offered on the Projects tab when you click the New... item in the File menu. When the dialog appears, select Win 32 Console Application and name the project Ex1_01; then click on OK.
Next, the Console Application dialog appears. We'll start from the very basic project structure, so choose An empty project, and click on the Finish button.
The New Project Information tells you about the project you're about to create; it should look something like this:
The project directory at the foot of the screen may be slightly different on your machine; everything else should be identical. Once your happy with it, click on OK.
We'll start by entering the following program as a new source file, so click the leftmost icon on the standard toolbar, , to create a new text file into which you can type the code.
Note that this code is available for download from the Wrox Press website: http://www.wrox.com, as are all of the code examples in this tutorial.// EX1_01.CPP
// A Simple Example of a Program
#include
using namespace std;
int main()
{
int apples, oranges; // Declare two integer variables
int fruit; // ...then another one
apples = 5; oranges = 6; // Set initial values
fruit = apples + oranges; // Get the total fruit
cout << endl; // Start output on a new line
cout << "Oranges are not the only fruit... " << endl
<< "- and we have " << fruit << " fruits in all.";
cout << endl; // Start output on a new line
return 0; // Exit the program
}
The above example is intended to illustrate some of the ways in which you can write C++ statements, rather than to be a model of good programming style.
Note that in the word endl ends with the letter l, not with the numeral 1.
Once you have keyed it in, save it as Ex1_01.cpp using the File menu Save As... option. The Save As dialog will offer to save it in the project directory that you just created and, since this file is part of that project, that's the best place for it. Since you have now identified the file by its extension as a file containing C++ code, the keywords in the code will gain their colors. You will be able to see if you have entered Int where you should have entered int, since the two will be different colors.
If you look at the FileView tab for your new project, you'll notice that the source file doesn't appear as part of the project's files. We need to add the file to the project using the Add to Project... item from the Project menu, or by right-clicking in the window containing the source and selecting Insert File into Project. Once this is done, you'll see the newly created source file in the FileView, and the main() function will appear under the Globals section of the ClassView. We'll consider the meaning of this later.
If you now build this program by using the Build button on the Project toolbar, , and execute it using the Execute Ex1_01.exe item in the Build menu, or by pressing the Execute Program button, , you should get the following output:

Program Comments
The first two lines in the C++ code are comments. Comments are an important part of any program, but they're not executable code - they are there simply to help the human reader. All comments are ignored by the compiler. On any line of code, two successive slashes // that are not contained within a text string (we shall see what text strings are later) indicate that the rest of the line is a comment.
You can see that several lines of the program contain comments as well as program statements. You can also use an alternative form of comment bounded by /* and */. For example, the first line of the program could have been written:/* EX1_01.CPP */
The comment using // only covers the portion of the line following the two successive slashes, whereas the /*...*/ form defines whatever is enclosed as a comment and can span several lines. For example, we could write:/*
EX1_01.CPP
A Simple Program Example
*/
All four lines are comments. If you want to highlight some particular comment lines, you can always embellish them with a frame of some description:/*****************************
* EX1-01.CPP *
* A Simple Program Example *
*****************************/
As a rule, you should always comment your programs comprehensively. The comments should be sufficient for another programmer, or you at a later date, to understand the purpose of any particular piece of code, and to understand how it works.
The #include Directive - Header Files
Following the comments, we have the #include directive,#include
which makes the compiler insert the contents of the file iostream into the program before compilation. This file is called a header file because it's usually brought in at the beginning of a program file. This particular header file contains definitions that are necessary for you to be able to use input and output statements in C++. If we didn't include iostream in our program, it wouldn't compile because we use output statements which depend on some of the definitions in this file. There are many different header files provided by Visual C++ and they cover a wide range of capabilities. We shall be seeing more of them as we progress through the language facilities.
A #include statement is one of several preprocessor directives. The Visual C++ editor recognizes these and highlights them in blue in your edit window (as it does with all the C++ keywords). Preprocessor directives are commands executed by the compiler that generally act on your source code in some way before it is compiled. They all start with the # character. We'll be introducing other preprocessor directives as we need them.
The using Directive - Namespaces
The standard library is an extensive set of routines which have been written to do many common tasks: for example, dealing with input and output, performing basic mathematical calculations, etc. Instead of writing these routines for yourself, you can simply pluck them out of the standard library and use them in your code. The file iostream is just one of a number of header files that contain the routines of the standard library. (You can see a full list of the standard library files in the online MSDN help files in Visual C++ Documentation \ Reference \ C/C++ Language and C++ Libraries \ Standard C++ Library Reference.)
The code for all of these standard library routines is contained within the namespace std. So, any standard library routine belongs to the namespace std. Each of the standard library header files contributes a few routines to the namespace std.
The code in our program does not belong to the namespace std. Therefore, to use the output routines in the iostream header file, we need to tell the compiler that the routines belong to the namespace std. In order to do this, we use the using directive:using namespace std;
With this line in our program, the compiler knows that we will be using routines that belong to the standard library. There are other ways of dealing with this, and we'll see those later, when we'll go into namespaces in more detail in Chapter 5, when we will be able to create our own namespaces.
The Function main()
The function main() in our example consists of the function header defining it as main() plus everything from the first opening curly brace, {, to the corresponding closing curly brace, },. The curly braces enclose the executable statements in the function, which are referred to collectively as the body of the function.
As we shall see, all functions consist of a header which defines (amongst other things) the function name, followed by the function body which consists of a number of program statements enclosed between a pair of curly braces. The body of a function may contain no statements at all, in which case it doesn't do anything.
A function that doesn't do anything may seem somewhat superfluous, but when you're writing a large program, you may map out the complete program structure in functions but, initially, leave the code for many of them with empty bodies. Doing this means that you can compile and execute the whole program with all its functions at any time, but add detailed coding for the functions incrementally.
Program Statements
The program statements making up the function body of main() are each terminated with a semicolon. The program statement is the basic unit in defining what a program does. This is a bit like a sentence in a paragraph of text, where each sentence stands by itself in expressing an action or an idea, but relates to and combines with the other sentences in the paragraph in expressing a more general idea. A statement is a self-contained definition of an action that the computer is to carry out, but which can be combined with other statements to define a more complex action or calculation.
The action of a function is always expressed by a number of statements, each ending with a semicolon. Let's take a quick look at each of the statements in the example that we have just written, just to get a general feel for how it works. We will discuss each type of statement more fully later in this chapter.
The first statement in the program,int apples, oranges; // Declare two integer variables
declares two variables, apples and oranges. A variable is a named bit of computer memory that you can use to store data. A statement introducing the names of variables is called a variable declaration. The keyword int indicates that the variables are to store values that are whole numbers, or integers. The next statement declares another integer variable, fruit. While you can declare several variables in the same statement, as we did for apples and oranges, it is generally a good idea to declare them separately. This enables you to comment them individually.
In the example, the line,apples = 5; oranges = 6; // Set initial values
contains two statements, each terminated by a semicolon. While it isn't obligatory, it's good programming practice to write only one statement on a line. The two statements store the values 5 and 6 in the variables apples and oranges respectively. These statements are called assignment statements, because they assign a new value to a variable.
The next statement,fruit = apples + oranges; // Get the total fruit
is also an assignment statement. This one adds the values stored in the variables apples and oranges and stores the result in the variable fruit.
The next three statements are:cout << endl; // Start output on a new line
cout << "Oranges are not the only fruit... " << endl
<< "- and we have " << fruit << " fruits in all.";
cout << endl; // Start output on a new line
These are all output statements. The first sends a newline character, denoted by the word endl, to the screen. In C++, a source of input or a destination for output is referred to as a stream. The word cout specifies the 'standard' output stream, and the operator << indicates that what appears to the right of the operator is to be sent to the output stream, cout. The operator << 'points' in the direction that the data flows - from the variable or string on the right to the output destination on the left.
The meaning of the word cout and the operator << are defined by the contents of the header file iostream, which you'll remember we added to our program code by placing the #include directive at the beginning of the program. Because cout has been defined to send the standard output stream to your display screen, you shouldn't use the word cout for other purposes - for example, as a variable in your program.
The second statement sends a text string (defined between quotes) to the screen, followed by another newline character (endl), then another text string, followed by the value stored in the variable fruit, then finally another text string. There is no problem stringing together a sequence of things that you want to output in this way. The statement executes from left to right, with each item being sent to cout in turn. Note that each item is preceded by its own << operator.
The third statement sends another newline character to the screen. These statements produce the output from the program that you see. Note that the second statement runs over two lines. The successive lines are combined into a single statement until the compiler finds the semicolon that defines the end of the statement. This means that if you forget a semicolon for a statement, the compiler will assume the next line is part of the same statement and join them together. This usually results in something the compiler cannot understand, so you'll get an error when you try to compile the code.
The last statement in our program,return 0; // Exit the program
stops execution of the program and returns control to the operating system. We will be discussing all of these statements in more detail later on.
The statements in a program are executed in the sequence in which they are written, unless a statement specifically causes the natural sequence to be altered. In Chapter 3, we will look at statements which alter the sequence of execution.
Whitespace
Whitespace is the term used in C++ to describe blanks, tabs, newline characters and comments. Whitespace separates one part of a statement from another and enables the compiler to identify where one element in a statement, such as int, ends and the next element begins. Therefore, in the statement,int fruit; // ...then another one
there must be at least one whitespace character (usually a space) between int and fruit for the compiler to be able to distinguish them. On the other hand, in the statementfruit = apples + oranges; // Get the total fruit
no whitespace characters are necessary between fruit and =, or between = and apples, although you are free to include some if you wish. This is because the = is not alphabetic or numeric, so the compiler can separate it from its surroundings. Similarly, no whitespace characters are necessary either side of the + sign.
Apart from its use as a separator between elements in a statement that might otherwise be confused, whitespace is ignored by the compiler (except, of course, in a string of characters between quotes). You can, therefore, include as much whitespace as you like to make your program more readable, as we did when we spread our output statement in the last example over several lines. In some programming languages, the end of a statement is at the end of the line, but in C++ the end of a statement is wherever the semicolon occurs.
Since variable names must be made up of single words, you must not put whitespace characters in the middle. If you do, the single variable name won't be seen by the compiler as such, and it won't be interpreted correctly.
Statement Blocks
We can enclose several statements between a pair of curly braces, in which case they become a block, or a compound statement. The body of a function is an example of a block. Such a compound statement can be thought of as a single statement (as we shall see when we look at the decision making possibilities in C++ in the next chapter. In fact, wherever you can put a single statement in C++, you could equally well put a block of statements between braces. As a consequence, blocks can be placed inside other blocks. In fact, blocks can be nested, one within another, to any depth.
A statement block also has important effects on variables, but we will defer discussion of this until later in this chapter when we discuss something called variable scope