Wednesday, October 10, 2007

II B.Tech I Semester Supplementary Examinations, February 2007ADVANCED DATA STRUCTURES & ALGORITHMS

II B.Tech I Semester Supplementary Examinations, February 2007ADVANCED DATA STRUCTURES & ALGORITHMS( Common to Information Technology and Computer Science & SystemsEngineering)Time: 3 hoursMax Marks: 80Answer any FIVE QuestionsAll Questions carry equal marks. . . . .
1. (a) What is di. between malloc()/free() and new/delete.
(b) What are the access privileges in C++. What is the default access level.
(c) What is destructor.(d) What is passing by reference.[4+4+4+4]
2. (a) What’s the deal with operator overloading.
(b) What are the benefits of operator overloading.
(c) What are some examples of operator overloading.
(d) What operators can/cannot be overloaded.[4+4+4+4]
3. (a) How can we provide printing for an entire hierarchy of classes.
(b) How can we open a stream in binary mode.
(c) How can we “reopen" std::cin and std::cout in binary mode.[5+5+6]
4. (a) What are the applications of stack explain with an example.
(b) Explain the list representation of a tree by means of an example.
(c) Mention some common computing times for algorithms in order of increasingdi.culty.[5+5+6]
5. (a) What is a dictionary. Define the abstract data type for it. Write the abstractclass for the dictionary.
(b) Give the applications of dictionary or dictionary with duplicates in whichsequential access is desired.[8+8]
6. What is a Binary search tree. Provide a specification for the abstract data typeBSTree(binary search tree with duplicates). Define a C++ abstract class thatcorresponds to this ADT. Write a program to insert a pair into a binary searchtree.[16]
7. Write and explain a non recursive algorithm for post order traversal of a Binarytree with an example.[16]
8. (a) Explain the Job sequencing with deadlines with an example using the greedyapproach.

B.Tech I Semester Supplementary Examinations, February 2007ADVANCED DATA STRUCTURES & ALGORITHMS

B.Tech I Semester Supplementary Examinations, February 2007ADVANCED DATA STRUCTURES & ALGORITHMS( Common to Information Technology and Computer Science & SystemsEngineering)Time: 3 hoursMax Marks: 80Answer any FIVE QuestionsAll Questions carry equal marks. . . . .
1. (a) Explain about Object Oriented Programming principles.
(b) Comapare C++ with C.[8+8]
2. Define Inheritance. How many types of inheritances are there. Explain each withsuitable examples.[16]
3. (a) How does that funky while (std :: cin >> foo) syntax work.
(b) Why does input seem to process past the end of file.
(c) Should we end output lines with std::endl or ‘\n'.[5+5+6]
4. (a) What are the applications of stack explain with an example.
(b) Explain the list representation of a tree by means of an example.
(c) Mention some common computing times for algorithms in order of increasingdi.culty.[5+5+6]
5. Develop a class for hash table using linear probing and neverUsed concept to handlean erase operation. Write complete C++ code for all the methods. Include amethod to reorganize the table when (say) 60% of the empty buckets have neverused equal to false. The reorganization should move pairs around as necessary andleave a properly configured hash table in which neverUsed is true for every emptybucket.[16]6. (a) Write a method to delete the pair with the largest key from a Binary SearchTree.
(b) Write a method to find the height of a Binary Search Tree.[8+8]
7. Write and explain an algorithm to determine if the AND/OR tree T is solvable.[16]8. (a) Write a linear time algorithm that generates the OBST from the root table.
(b) Prove that the greedy method always obtains an optimal solution to the job-sequencing problem.[8+8]

2II B.Tech I Semester Supplementary Examinations, February 2007ADVANCED DATA STRUCTURES & ALGORITHMS

Code No: R059211201Set No. 2II B.Tech I Semester Supplementary Examinations, February 2007ADVANCED DATA STRUCTURES & ALGORITHMS( Common to Information Technology and Computer Science & SystemsEngineering)Time: 3 hoursMax Marks: 80Answer any FIVE QuestionsAll Questions carry equal marks. . . . .
1. (a) Explain about the friend function with a suitable example.
(b) Why is it best to use inline functions instead of plain old # define macros.
(c) How to tell the compiler to make a non-member function inline.
(d) How to tell the compiler to make a member function inline. [4+4+4+4]
2. What do you mean by run time polymorphism and how to implement run timepolymorphism using virtual functions in C++.[16]
3. (a) How do I use exceptions.
(b) Can I throw an exception from a constructor. From a destructor.
(c) Why doesn’t C++ provide a “finally" construct.
(d) What is an autoptr and why isn’t there an autoarray.
(e) Why can’t I resume after catching an exception.[3+3+3+3+4]
4. (a) What are the applications of stack explain with an example.
(b) Explain the list representation of a tree by means of an example.
(c) Mention some common computing times for algorithms in order of increasingdi.culty.[5+5+6]
5. (a) Explain the linear probing method in Hashing. Explain its performance analy-sis.
(b) What is hashing with Chains. Explain. Compare this with Linear Probing.[8+8]
6. (a) Prove that the insertion of a new node in a red-black tree with n nodes in .(logn) time in the worst case.
(b) Derive the amortized complexity of a find, insert or delete operation performedon a splay tree with n elements.[8+8]
7. (a) Explain the Binary tree in order traversal in o(n) and 0(1) space.
(b) Explain divide and conquer strategy by means of its control abstraction.(c) What is the di.erence between Greedy method and Divide and conquer.[6+6+4]
8. (a) What are the general characteristics of greedy algorithms and the problemssolved by these algorithms.
(b) What is 0/1 Knapsack problem. Explain how principle of optimality appliesto it. Also derive its dynamic recurrence relation.[8+8]

1II B.Tech I Semester Supplementary Examinations, February 2007ADVANCED DATA STRUCTURES & ALGORITHMS

Code No: R059211201Set No. 1II B.Tech I Semester Supplementary Examinations, February 2007ADVANCED DATA STRUCTURES & ALGORITHMS( Common to Information Technology and Computer Science & SystemsEngineering)Time: 3 hoursMax Marks: 80Answer any FIVE QuestionsAll Questions carry equal marks. . . . .
1. (a) What do you mean by Data abstraction.
(b) Di.erence between “C structure" and “C++ structure"..
(c) Di.rence between a “assignment operator" and a “copy constructor".
(d) What is the di.erence between overloading and “overridding". [4+4+4+4]
2. (a) What is multilevel inheritance. Write a program to illustrate the concept ofMultilevel Inheritance.
(b) What is Hybrid inheritance. Write a program to illustrate the concept ofHybrid Inheritance.[8+8]
3. What is an Error and Exception. Explain the exception handling mechanism inC++ .[16]
4. (a) What are the applications of stack explain with an example.
(b) Explain the list representation of a tree by means of an example.
(c) Mention some common computing times for algorithms in order of increasingdi.culty.[5+5+6]
5. Develop a class for hash table using linear probing and neverUsed concept to handlean erase operation. Write complete C++ code for all the methods. Include amethod to reorganize the table when (say) 60% of the empty buckets have neverused equal to false. The reorganization should move pairs around as necessary andleave a properly configured hash table in which neverUsed is true for every emptybucket.[16]6. (a) Write a method to delete the pair with the largest key from a Binary SearchTree.(b) Write a method to find the height of a Binary Search Tree.[8+8]
7. Write and explain an algorithm to determine if the AND/OR tree T is solvable.[16]8. (a) Write a linear time algorithm that generates the OBST from the root table.(b) Prove that the greedy method always obtains an optimal solution to the job-sequencing problem.[8+8]

4II B.Tech I Semester Regular Examinations, November 2006ADVANCED DATA STRUCTURES & ALGORITHMS

Code No: R059211201Set No. 4II B.Tech I Semester Regular Examinations, November 2006ADVANCED DATA STRUCTURES & ALGORITHMS( Common to Information Technology and Computer Science & SystemsEngineering)Time: 3 hoursMax Marks: 80Answer any FIVE QuestionsAll Questions carry equal marks. . . . .
1. (a) What is the di.erence between global static functions and static functions,class members.
(b) What is common and what is the di.erence between implementations of thecopy constructors, initialization and overloaded assignment operators.
(c) What is the di.erence between modifiers register, const and volatile. [5+5+6]
2. (a) Write a program to illustrate the concept of virtual base class with exampleprogram.
(b) How to implement run time polymorphism using virtual functions. [8+8]
3. (a) Explain about console I/O and formatted I/O streams in C++.
(b) Write a program to count the no of lines in given text file.[8+8]
4. Write and explain UNION and find algorithms with weighting and collapsing rule.[16]
5. Develop a class for hash table using linear probing and neverUsed concept to handlean erase operation. Write complete C++ code for all the methods. Include amethod to reorganize the table when (say) 60% of the empty buckets have neverused equal to false. The reorganization should move pairs around as necessary andleave a properly configured hash table in which neverUsed is true for every emptybucket.[16]
6. Define a Binary Search Tree. Write the procedures to perform insertion, deletionand searching in a binary search tree.[16]
7. (a) Explain the Binary tree in order traversal in o(n) and 0(1) space.
(b) Explain divide and conquer strategy by means of its control abstraction.
(c) What is the di.erence between Greedy method and Divide and conquer.[6+6+4]
8. (a) What are the general characteristics of greedy algorithms and the problemssolved by these algorithms.
(b) What is 0/1 Knapsack problem. Explain how principle of optimality appliesto it. Also derive its dynamic recurrence relation.[8+8]

3II B.Tech I Semester Regular Examinations, November 2006ADVANCED DATA STRUCTURES & ALGORITHMS

Code No: R059211201Set No. 3II B.Tech I Semester Regular Examinations, November 2006ADVANCED DATA STRUCTURES & ALGORITHMS( Common to Information Technology and Computer Science & SystemsEngineering)Time: 3 hoursMax Marks: 80Answer any FIVE QuestionsAll Questions carry equal marks. . . . .

1. (a) What do you mean by Stack unwinding.
(b) What is the di.erence between const char *myPointer and char *const
(c) Define precondition and post-condition to a member function.
(d) What are the conditions that have to be met for a condition to be an invariantof the class.[4+4+4+4]
2. (a) Explain the need for “Virtual Destructor".
(b) Can we have “Virtual Constructors".[8+8]
3. (a) What are some ways try / catch / throw can improve software quality.
(b) How can we handle a constructor that fails.
(c) How can we handle a destructor that fails.[5+5+6]
4. (a) What are the applications of stack explain with an example.
(b) Explain the list representation of a tree by means of an example.
(c) Mention some common computing times for algorithms in order of increasingdi.culty.[5+5+6]
5. What is Hashing. Explain the di.erent Hash table representations in detail. [16]6. Define a class called binarySearchTree to represent a Binary search tree. Extendthis class by adding a public method outputInRange (Low,High) that outputs,in ascending order of key, all elements in a binary search tree whose key lies betweenLow and High. Use recursion and avoid entering sub trees that cannot possiblycontain any elements with keys in desired range.[16]
7. (a) Explain the Binary tree in order traversal in o(n) and 0(1) space.(b) Explain divide and conquer strategy by means of its control abstraction.
(c) What is the di.erence between Greedy method and Divide and conquer.[6+6+4]
8. (a) Explain the Job sequencing with deadlines with an example using the greedyapproach.
(b) Describe the dynamic programming approach for the construction of OBSTfor a set of n keys, if all keys are equally likely to be searched for. [8+8]

B.Tech I Semester Regular Examinations, November 2006ADVANCED DATA STRUCTURES & ALGORITHMS

Code No: R059211201Set No. 2II B.Tech I Semester Regular Examinations, November 2006ADVANCED DATA STRUCTURES & ALGORITHMS( Common to Information Technology and Computer Science & SystemsEngineering)Time: 3 hoursMax Marks: 80Answer any FIVE QuestionsAll Questions carry equal marks. . . . .

1. (a) What are the two steps that happen with delete p.
(b) What are the advantages of new operator than malloc in C.
(c) Explain about the C++ classes in detail and design a class for playing cards.[5+5+6]
2. What is template. Explain about function templates and class templates withsuitable examples.[16]
3. (a) Write a program to change the case of each word in a file to initial capitals.(b) Write a program to concatenate the two given strings.[8+8]
4. What are the di.erent mathematical notations used for algorithm analysis. 16]
5. Develop a class for hash table using linear probing and neverUsed concept to handlean erase operation. Write complete C++ code for all the methods. Include amethod to reorganize the table when (say) 60% of the empty buckets have neverused equal to false. The reorganization should move pairs around as necessary andleave a properly configured hash table in which neverUsed is true for every emptybucket.[16]6. What is an AVL Tree. Write the algorithm to search for an element of an AVLSearch Tree. What is its time complexity.[16]
7. (a) Explain the Binary tree in order traversal in o(n) and 0(1) space.
(b) Explain divide and conquer strategy by means of its control abstraction.
(c) What is the di.erence between Greedy method and Divide and conquer.[6+6+4]
8. (a) What are the general characteristics of greedy algorithms and the problemssolved by these algorithms.
(b) What is 0/1 Knapsack problem. Explain how principle of optimality appliesto it. Also derive its dynamic recurrence relation.[8+8]

II B.Tech I Semester Regular Examinations, November 2006

Code No: R059211201Set No. 1 II B.Tech I Semester Regular Examinations, November 2006ADVANCED DATA STRUCTURES & ALGORITHMS( Common to Information Technology and Computer Science & SystemsEngineering)Time: 3 hoursMax Marks: 80Answer any FIVE QuestionsAll Questions carry equal marks. . . . .
1.
(a) What is the default data hiding type for a class. Why are data membershidden. How would you access them.
(b) In a printf statement, what are the codes for integer. .oat. string. How canyou choose how many numbers occur before and after the decimal point fora .oat. How can you pad zeroes to the beginning of an integer to make it aspecific length.[8+8]
2. What do you mean by run time polymorphism and how to implement run timepolymorphism using virtual functions in C++.[16]
3. (a) What are some ways try / catch / throw can improve software quality.(b) How can we handle a constructor that fails.(c) How can we handle a destructor that fails.[5+5+6]
4. (a) What are the applications of stack explain with an example.
(b) Explain the list representation of a tree by means of an example.
(c) Mention some common computing times for algorithms in order of increasingdi.culty.[5+5+6]
5. Develop a class for hash table using linear probing and neverUsed concept to handlean erase operation. Write complete C++ code for all the methods. Include amethod to reorganize the table when (say) 60% of the empty buckets have neverused equal to false. The reorganization should move pairs around as necessary andleave a properly configured hash table in which neverUsed is true for every emptybucket.[16]6. What is an AVL Tree. Write the algorithm to search for an element of an AVLSearch Tree. What is its time complexity.[16]
7. (a) Explain the Binary tree in order traversal in o(n) and 0(1) space.
(b) Explain divide and conquer strategy by means of its control abstraction.(c) What is the di.erence between Greedy method and Divide and conquer.[6+6+4]
8. (a) Explain the Job sequencing with deadlines with an example using the greedyapproach

Saturday, October 6, 2007

Algorithm for DFS

Algorithm DFS(v)
//Given an undirected (directed) graph
//G=(v,E) with n vertices and an array visited[] initially set to zero
//ther algorithm visits all vertices reachable from v. G and visited are global.
{
visited[v]:=1;
for each vertex w adjacent from v do
{
if(visited[w]=0) then DFS(w);
}
}

Algorithm for BFS

Algorithm BFS(v)
//A breadth first search of G is carried out begining at vertex v. For any node i
//visited[i]=1 if i has already been visited. The graphs G and arry visited are
//global, visited is initialized to zero
{
u:=v;//q is a queue of unexplored vertices
visit[v]:=1;
repeat
{
for all vertices w adjacent from u do
{
if(visited[w]=0) then
{
Add w to q;//w is unexplored
visited[w]:=1;
}
}
if q is empty then return;
delete u from q;
}until(false);
}


Algorithm BFT(G,n)
//Breath first traversal of G
{
for i:=1 to n do //Mark all vertices on visited
visit[i]:=0;
for i:=1 to n do if(visited[i]=0) then BFS(i);
}

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.