ALGORITHM OF DIFFERENT C++ PROGRAMMES
(1)Algorithm to implement a class template
Sol:
1. create a template class
2. then create a class c
Private section:-
A array a[5]specification with anomous type T
Public section:-
(a) A member function get() for input the array.
(b) A member function show() for display.
3. In main we create a class object a of integer type i.e ca and a nother object of float type
4. Then we call the two function get() and show throw these object.
5. End of programe.
(2)Algorithm to implement a function template
sol:
1. Define the prefix template
2. Create a function sum of template type with template argume nt i.e.
T sum(T a, T b)
3. Then take another template type variable and add a& b and return c i.e.
C= a+b
4. In main call the sum function first with integer variable then character variable 7 get desire output.
5. End of programe.
(3)Algorithm to implement exception handling in a prog
Sol:
1. initialize x,y,z with float data type
2. enter the value of x ,y, & z.
3. then initlize try block & check whether x equal to y .
4. If x is equal to y then throw exception x-y.
5. Else z/x-y.
6. This exception throw by throw statement caught by catch block & execute it.
7. End of the programe.
(4)Algorithm to implement a virtual base class
Sol:-
1. create a base class stu
Protected section: data member rno of integer type.
Public section:
( a) member function getrno ()for input rno
(c) member function putrno() for displat rno.
2. create another class test & make it virtual to base class stu which is inherited in public mode
Protected: data members m1 7 m2 of integer type.
Public:
(a) member function getmarks(int x, int y) input the marks in two subject.
(b) member function putmarks() for display the marks.
3. create another class sport & make it virtual to base class stu which is inherited in public mode
Protected: data members score of integer type.
Public: (a) member function getscore(int n) input the score.
(b) member function putscore() for display the score.
4. in main create an object of class test t & another object of class sport s.
5. throw t & s we call the member function of classes and get our result.
6. end of programe.
(5).Algorithm to implement hybrid inheritance
Sol:
1. create a class student
protected section: a string of name[20].
Public section:
(a)member function getname () for input name
(b) member function showname() for display name.
2. create an another class test publically inherit student and make it virtual
Protected section: data member marks1, marks2 of integer type.
Public section:
(a) member function getmarks() for input marks
(b) member function showmarks() for display marks.
3. create another class game publicaly inherit student and make it virtual
Protected section: data member score of integer type.
Public section:
(a) member function getscore() for input score.
(b) member function showscore() for display score.
4. create an another class which publically inherited classes test & game it show hybrid inheritance
Private section: datamember total of integer type.
Public section:
(a) member function showresult() which show the total marks
(b) call showname(),showmarks() & show scrore().
5 in main create an object of class result as st.
6 call getname().
7. call getmarks().
8. call getscore().
9. call showresult().
10. end of programe
Why Use a Disk?
If you've worked with computers very much, and if you've done some programming in other languages, you know the importance of file storagefor data. The typical computer system has much less memory storage than hard disk storage. Your disk drive holds much more data than can fit in your computer's RAM. The disk memory, because it is nonvolatile, lasts longer because the disk retains its contents when you power-off your computer. Also, when your data changes, you (or more important, your users) do not have to edit the program and look for a set of assignment statements. Instead, the users run previously writtenprograms that make changes to the disk data.
Types of Disk File Access
Your programs can access files two ways: through sequential access or random access. Your application determines the method you should choose. The access mode of a file determines how you read, write, change, and delete data from the file. Some of your files can be accessed in both ways, sequentially and randomly, as long as your programs are written properly and the data lends itself to both types of file access.
A sequential file must be accessed in the same order the file was written. This is analogous to cassette tapes: You play music in the same order it was recorded. (You can quickly fast-forward or rewind through songs that you do not want to listen to, but the order of the songs dictates what you do to play the song you want.) It is difficult, and sometimes impossible, to insert data in the middle of a sequential file. How easy is it to insert a new song in the middle of two other songs on a tape? The only way to truly add or delete records from the middle of a sequential file is to create a completely new file that combines both old and new songs.
It might seem that sequential files are limiting, but it turns out that many applications lend themselves to sequential file processing.
Unlike with sequential files, you can access random access files in any order you want. Think of data in a random access file as you would think of songs on a compact disc or a record; you can go directly to any song you want without having to play or fast-forward through the other songs. If you want to play the first song, the sixth song, and then the fourth song, you can do so. The order of play has nothing to do with the order in which the songs appear on the recording. Random file access sometimes takes more programming but rewards that effort with a more flexible file access method. You'll learn about both file storage methods in this chapter.
Learning Sequential File Concepts
There are three operations you can perform on sequential disk files. You can
• Create disk files
• Add to disk files
• Read from disk files
Your application determines what you need to do. If you are creating a disk file for the first time, you must create the file and write the initial data to it. Suppose that you wanted to create a customer data file. You would create a new file and write your current customers to that file. The customer data might originally be in arrays or arrays of structures, pointed to with pointers, or typed into regular variables by the user.
Over time, as your customer base grows, you can add new customers to the file. When you add to the end of a file, you append to that file. As your customers enter your store, you would read their information from the customer data file.
Customer disk processing brings up one disadvantage of sequential files, however. Suppose that a customer moves and wants you to change his or her address in your files. Sequential access files do not lend themselves well to changing data stored in them. It is also difficult to remove information from sequential files. Random files will provide a much easier approach to changing and removing data. The primary approach to changing or removing data from a sequential access file is to create a new one from the old one with the updated data.
Opening and Closing Sequential Files
Before you can create, write to, or read from a disk file, you must open the file. This is analogous to opening a file cabinet before working with a file stored in the cabinet. As soon as you are done with a cabinet's file, you close the file door. You must also close a disk filewhen you finish with it.
When you open a disk file, you must inform C only of the filename and what you want to do (write to, add to, or read from). C and youroperating system work together to make sure that the disk is ready, and they create an entry in your file directory (if you are creating a file) for the filename.
When you close a file, C writes any remaining data to the file, releases the file from the program, and updates the file directory to reflect the file's new size.
To open a file, you must call the fopen() function (for ''file open"). To close a file, call the fclose() function. Here is the format of these two function calls:
filePtr = fopen(fileName, access);
and
fclose(filePtr);
a definition in the stdio.h header file. The examples that follow show you how to define a file pointer.The filePtr is a special type of pointer that points only to files, not to data variables. You must define a file pointer with FILE
Your operating system handles the exact location of your data in the disk file. You do not want to worry about the exact track and sector number of your data on the disk. Therefore, you let the filePtr point to the data you are reading and writing. Your program only has to generically manage the filePtr while C and the operating system take care of locating the actual physical data.
The fileName is a string (or a character pointer that points to a string) containing a valid filename for your computer. If you are using a PC or a UNIX-based computer, the fileName can contain a complete disk and directory pathname. If you are using a mainframe, you must use the complete dataset name in the fileName string. Generally, you can specify the filename in uppercase or lowercase letters, as long as your operating system does not have a preference.
Sometimes you see programs that contain a t or a b in the access mode, such as ''rt" or "wb+". The t means text file and is the default mode; each of the access modes listed in Table 24.1 is equivalent to using t after the access mode letter ("rt" is identical to "r", and so on). A text file is an ASCII file, compatible with most other programming languages and applications. Text files do not always contain text, in the word processing sense of the word. Any data you need to store can go in a text file. Programs that read ASCII files can read data you create as C text files. The b in the access mode means binary mode.
If you open a fil for writing (using access modes of "w", "wt", "wb", or "w+"), C creates the file. If a file by that name already exists, C overwrites the old file with no warning. When opening files, you must be careful that you do not overwrite existing data you want to save.
If an error occurs during the opening of a file, C does not return a valid file pointer. Instead, C returns a file pointer equal to the value NULL. NULL is defined in stdio.h. For example, if you open a file for output, but use a disk name that is invalid, C cannot open the file and will make the file pointer point to NULL. Always check the file pointer when writing disk file programs to ensure that the file opened properly.
Writing to a File
Any input or output function that requires a device performs input and output with files. You have seen most of these already. The most common file I/O functions are
getc() and putc()
fprintf()
fgets() and fputs()
There are a few more, but the most common I/O function left that you have not seen is the fscanf() function. fscanf() is to scanf() as fprintf() is to printf(). The only difference between fscanf() and scanf() is its first parameter. The first parameter to fscanf() must be a file pointer (or any C device, such as stdin and stdaux).
The following function reads three integers from a file pointed to by filePtr:
fscanf(filePtr, "%d %d %d", &num1, &num2, &num3);
As with scanf(), you do not have to specify the & before array variable names. The following fscanf() reads a string from the disk file:
fscanf(filePtr, "%s", name);
The fscanf() is not as potentially dangerous as the scanf() function. scanf() gets input from the user. The user does not always enter data in the format that scanf() expects. When you get data from a disk file, however, you can be more certain about the format because you probably wrote the program that created the file in the first place. Errors still can creep into a data file, and you might be wrong about the file's format when using fscanf(), but generally, fscanf() is more secure than scanf().
There is always more than one way to write data to a disk file. Most of the time, more than one function will work. For instance, if you write many names to a file, both fputs() and fprintf() will work. You also can write the names using putc(). You should use whichever function you are most comfortable with for the data being written. If you want a newline character (\n) at the end of each line in your file, the fprintf() and fputs() probably are easier than putc(), but all three will do the job.
Writing to a Printer
The fopen() and other output functions were not designed to just write to files. They were designed to write to any device, including files, the screen, and the printer. If you need to write data to a printer, you can treat the printer as if it were a file. The following program opens a FILE pointer using the MS-DOS name for a printer located at LPT1 (the MS-DOS name for the first parallel printer port):
Adding to a File
You can easily add data to an existing file or create new files by opening the file in append access mode. Data files on the disk rarely are static; they grow almost daily due to (with luck!) increased business. Being able to add to data already on the disk is very useful indeed.
Files you open for append access (using ''a", "at", "ab", "a+b", and "ab+") do not have to exist. If the file exists, C appends data to the end of the file when you write the data. If the file does not exist, C creates the file (as is done when you open a file for write access).
Reading from a File
As soon as the data is in a file, you must be able to read that data. You must open the file in a read access mode. There are several ways to read data. You can read character data a character at a time or a string at a time. The choice depends on the format of the data. If you stored numbers using fprintf(), you might want to use a mirror-image fscanf() to read the data.
Files you open for read access (using ''r", "rt", and "rb") must exist already, or C gives you an error. You cannot read a file that does not exist. fopen() returns NULL if the file does not exist when you open it for read access.
Another event happens when reading files. Eventually, you read all the data. Subsequent reading produces errors because there is no more data to read. C provides a solution to the end-of-file occurrence. If you attempt to read from a file that you have completely read the data from, C returns the value EOF, defined in stdio.h. To find the end-of-file condition, be sure to check for EOF when performing input from files.
Random File Records
Random files exemplify the power of data processing with C. Sequential file processing is slow unless you read the entire file into arrays and process them in memory. Random files provide you a way to read individual pieces of data from a file in any order needed and process them one at a time.
Generally, you read and write file records. A record to a file is analogous to a C structure. A record is a collection of one or more data values (called fields) that you read and write to disk. Generally, you store data in structures and write the structures to disk, where they are called records. When you read a record from disk, you generally read that record into a structure variable and process it with your program.
Unlike some other programming languages, not all C-read disk data has to be stored in record format. Typically, you write a stream of characters to a disk file and access that data either sequentially or randomly by reading it into variables and structures.
The process of randomly accessing data in a file is simple. Consider the data files of a large credit card organization. When you make a purchase, the store calls the credit card company to get an authorization. Millions of names are in the credit card company's files. There is no quick way the credit card company could read every record sequentially from the disk that comes before yours. Sequential files do not lend themselves to quick access. In many situations, looking up individual records in a data file with sequential access is not feasible.
The credit card companies must use a random file access so that their computers can go directly to your record, just as you go directly to a song on a compact disc or a record album. The functions you use are different from the sequential functions, but the power that results from learning the added functions is worth the effort.
In this article we will discuss one of the most useful linear data structure – Stack as well as its implementation in C language and C++ languages. Firstly we will implement the algorithms used in stacks in C language and then we will study stacks in C++ using templates. We will also discuss why stacks play an important role in computer science. Definition and Examples A stack is a collection of elements in which all insertions and deletions are made at one end, called the top of the stack. It means that new elements are inserted at the ‘top’ of stack and elements are also deleted from the ‘top’ of the stack. Therefore it is the ‘top’ of stack that changes whenever an element is inserted or deleted. A stack of trays or of plates is a simple example of stack, as shown in figure-1. Figure 1 When we use the word ‘stack’ in a programming context then one should remember that the elements of a stack should be of similar data types and these elements can be of either built-in data types or user-defined data types. Figure-2 is a motion picture of a stack as it expands and shrinks with the passage of time. If a stack has five elements, say A, B, C, D and E, then it is represented as shown in figure-2(a). From this figure it is clear that the element ‘E’ is at the topmost position of stack and ‘A’ is at the bottom most position.Now if we want to insert a new element ‘F’ then after the insertion, the element ‘F’ will be the top element of the stack as shown in figure-2(b). Again if we want to insert another element then it will be placed on the top of ‘F’. Figure-2(c) represents insertion of two new elements ‘G’ and ‘H’ respectively. Now if we want to delete any element from the stack then ‘H’ will be the first element to be deleted. Figure-2(d) shows the deletion of a element from the stack. From the pictorial representation of figure-2, it is clear that the last element to be inserted into a stack is the first element to be deleted. That’s why the stack is also called as Last-In First-Out (LIFO) data structure. Figure 2 Operations on Stacks Generally we perform two basic operations onto a stack – push and pop. When we insert a new element to a stack, it is called as pushed onto the stack and when we delete an element, it is called as popped from the stack. Because of this operation, a stack is also called as Push-down lists. For example, if ‘S’ represent a stack and ‘item’ represents an element to be pushed then the push operation is written as:
Introduction Push(S, item);
Similarly when we pop an element from a stack, it is represented as:
item = Pop(S)
where ‘S’ represents a stack. For example, if ‘S’ is the stack of figure-2(a) we perform the following operations from 2(b) to 2(d).
Push(S, ‘F’);Push(S, ‘G’);
Push(S, ‘H’);
Pop(S)
However we can also perform some other operations on stacks as:
Intialize(S) – Initializes a stack S as an empty stack
StackTop(S) – returns the top element of stack S without removing it from the stack
IsStackFull(S) – checks whether the stack is full or not. If the stack is full then returns 1; otherwise returns 0.
IsStackEmpty(S) - checks whether the stack is empty or not. If the stack is empty then returns 1; otherwise returns 0.
The StackTop(S) function returns the top element of stack, only when the stack is not empty. If the stack is empty then it is not possible to return the top element. Similarly a Pop(S) function is possible only when the stack is not empty. Actually the StackTop() is not a new operation since it can be decomposed into a Pop() and Push(). Thus
item = StackTop(S);
is decomposed into following two operations:
item = Pop(S);Push(S, item);
Therefore before performing these two operations, we must ensure that the stack is not empty by invoking IsStackEmpty() function. Likewise a new element is inserted only when the stack is not full and it is ensured by invoking IsStackFull() function.
Therefore when we build a stack then it is necessary to implement these six operations.
Implementation of Stacks in C
In this section we will study how to represent a stack in a programming language ‘C’. However there are several ways to represent a stack in ‘C’. We can use either an array or a linked list while implementing a stack. Firstly we will see array implementation of stacks.
Array Implementation of Stacks
A stack is an ordered collection of elements. We know that an array contains an ordered collection of elements. Therefore a stack may be represented as a linear array in the computer memory that will store the elements in the stack. Therefore whenever we use array implementation of stack, we attempt to begin a program by declaring a variable ‘Stack’ as an array. We will also use a counter variable ‘top’ to indicate the current top element’s position within array. One end of the array is fixed, say bottom of the stack, while the value of ‘top’ constantly changes as elements are pushed and popped. In this type of implementation, we will also use another simple variable ‘Size’ to indicate the maximum number of elements that can be held by the stack.
A stack in ‘C’ is represented as
#define Size 50int top;
datatype Stack[Size];
Here we have used ‘Stack’ as an array name. However a stack and an array ‘Stack’ are two entirely different things. In general, one can not change the number of elements in an array because it is fixed and assigned by the declaration for the array. On the other hand, a stack is fundamentally a dynamic object whose size is constantly changing as items are pushed and popped. So we declare an array as there is enough space for the maximum size of the stack because the stack may grow and shrink within the space reserved for it.
In the above declaration, ‘Size’ is a constant giving the maximum number of elements allowed for stack, such that the stack will at no time contains more than Size elements (50 elements). In this example, the stack can contain 50 elements (from stack[0] to Stack[49]). The datatype is the type describing the data that will be put into the stack and ‘top’ is an integer variable to indicate the location of the top element of the stack. If the value of top is equal to –1 then it means that the stack is empty; otherwise not. Similarly if the value of top is equal to (Size-1), that is 49, then it means that the stack is full; otherwise not.
Here is the declaration for a stack of 50 integers:
#define Size 50int top;
int Stack[Size];
There is, of course, no reason to restrict a stack to contain only integers, we can also declare as:
float Stack[Size];char Stack[Size];
We can even construct a stack of user-defined data types, such as struct, as:
#define Size 50int top;
struct Employee
{
char name[25];
int age;
float salary;
};
struct Employee Stack[Size];
In fact, should the need arise, a stack can contain objects of different types by using ‘C’ unions. But for the sake of simplicity we will consider a stack of integers only. Figure-3 shows an array implementation of such stack.
Figure 3
Here the value of ‘top’ is 5. It means that there are six elements in the stack. It is because in ‘C’ and C++ array numbering starts from 0 and since Size is equal to 50 therefore we can push forty four more elements in the stack.
Now let us see some routines that are to be performed on stacks.
Initializing an Empty Stack
The Initialize() function is used to initialize a stack to empty before it is first used in a program. A stack is initialized by assigning value –1 to ‘top’ variable.
Here is the function that implements this task.
Initialize()
{
top=-1;
}
Is Stack Full or Not
When we insert an element onto the stack, then firstly we check whether the stack is full or not. If the stack is not full then the new element is inserted successfully; otherwise an error message is reported. Therefore while implementing this task we must check the value of ‘top’. If the value of ‘top’ is equal to (Size-1) then it means that the stack is full; otherwise not.
Here is the function that implements this task.
IsStackFull()
{
if (top==Size-1)
return 1;
else
return 0;
}
Is Stack Empty or Not
This condition is tested whenever we attempt to perform a pop operation. An element is removed from the stack only when the stack is not empty. Here again while implementing this task we must check the value of ‘top’. If the value of ‘top’ is equal to -1 then it means that the stack is empty; otherwise not.
Here is the function that implements this task.
IsStackEmpty()
{
if (top==-1)
return 1;
else
return 0;
}
Now the question arises – what is the need to define the function IsStackEmpty() when we could just as easily write if (top == -1) each time we want to test for the empty condition? There is no complicated reason behind this. Of course one can write if (top == -1) each time, but a good programmer wishes to make his/her program more comprehensible as well as concern with the readability of his/her code. It will definitely save a large amount of time in debugging the program because large-and-medium sized program will almost never be correct the first time they are run. Therefore if you want to be a mature programmer then concern with the proper balance of code economy and code clarity.
Pop Operation
When we implement Pop() operation we should consider the situation where we try to perform the pop operation on an empty stack. If our stack is empty and we perform pop operation then it should display just an error message that “Stack is Underflow” and the control is returned back. However if the stack is not empty then the top element of the stack is stored in a temporary local variable and the value of the ‘top’ is decremented. Finally this retrieved value is returned back.
Here is the algorithm that pops an element from the non-empty stack.
Algorithm : Pop
Pop(Stack)
Here ‘Stack’ contains the base address of the array ‘Stack’.
- Step-1 : Check whether Stack is empty or not. If Stack is empty then flash an error message – Stack underflow and go to step-4 otherwise go to step-2
- Step-2 : Access the top element of the stack as: Item = Stack[top]
- Step-3 : Decrement the value of top as top = top-1
- Step-4 : Exit
Here is the ‘C’ implementation of this algorithm.
Implementation : PopPop(int Stack[])
{
int item;
if (IsStackEmpty())
{
printf("\nStack Underflow. ");
exit(0);
}
item=Stack[top];
top--;
return (item);
}
This Pop() function can be used as:
item = Pop(Stack);
Here ‘item’ contains the value popped from the stack. Of course the programmer should ensure that the stack is not empty when the Pop() operation is called. If the programmer is not known to the state of the stack, its status may be determined by the coding
if (!IsStackEmpty())
item = Pop(Stack);
else
/* Take some remedial action because stack is empty */
However if programmer calls Pop() function knowingly or unknowingly with an empty stack then it will definitely terminate the execution of a program in the middle of its execution. Therefore it is totally programmer’s responsibility to consider the possibility of error and diagnose this error.
Testing for Exceptional Condition
However it might be more desirable for the Pop() function to signal the calling program that an underflow has occurred. The calling function upon detecting this signal can take appropriate remedial action. For this we will take another variable ‘flag’ which is initially set to 0. This variable is set to 1 only when we try to pop an element from an empty stack.
Let we name such function PopAndTest. Here is the definition of PopAndTest() function which pops and returns an indication whether an underflow has occurred.
PopAndTest(int Stack[], int *item, int *flag)
The following code segment uses this above function as:
{
if (IsStackEmpty())
{
*flag = 1;
return;
}
*flag = 0;
*item = Stack[top];
top --;
}
PopAndTest(Stack, &item, &flag);
Push Operation
if (flag == 1)
{
/* Take some remedial action because stack was empty */
}
else
/* Use value of item */
….
When we push an element onto a stack then we must first check whether the stack is full or not. If the stack is full then there is no place in the stack and the result of such an attempt is called an overflow. Therefore it should display just an error message – Stack is overflow and the control is returned back. If the stack is not full then the value of ‘top’ is incremented first and in last the new element is inserted at this new top position of the stack.
Here is the algorithm that pushes an item into a stack.
Algorithm : Push
Push(Stack, item)
Here ‘Stack’ contains the base address of the array ‘Stack’ and ‘item’ be the item to be pushed.
- Step-1 : Check Stack is full or not. If Stack is full then flash an error message – Stack overflow and go to step-4;otherwise go to step-2
- Step-2 : Increment the value of top as top = top+1
- Step-3 : Store the value of ‘item’ at top position a Stack[top] = item
- Step-4 : Exit
Here is the ‘C’ implementation of this algorithm.
Implementation : PushPush(int Stack[], int item)
In this function, we have called another function IsStackFull() which is used to test whether the stack is full or not. Here again if and when an overflow is detected, nothing could be pushed onto stack and execution of the program terminates immediately after an error message is displayed. In such case, the programmer must take some remedial action as we have seen in PopAndTest function. Let we call such push function as PushAndTest. Here is the implementation of PushAndTest().
{
if (IsStackFull())
{
printf("\nStack Overflow");
exit(0);
}
top++;
Stack[top]=item;
}
PushAndTest(int Stack[], int item, int *flag)
The following code segment uses this above function as:
{
if (IsStackFull())
{
*flag = 1;
return;
}
*flag = 0;
top++;
Stack[top]=item;
}
PushAndTest(Stack, item, &flag);
if (flag == 1)
{
/* Take some remedial action because item was not pushed on stack */
}
else
/* Item was successfully pushed on the stack */
….
Accessing Top Element of Stack
Sometimes we need to retrieve the top element of the stack without removing it from the stack. This operation is also called as ‘peek’ operation. Here it is also necessary to check firstly that the stack is empty or not. If not, then the topmost element is retrieved immediately; otherwise an error message is reported.
Remember that accessing top most element is not a primitive operation, because it can be decomposed into two operations as:
item=Pop(Stack);
But it does not look good to retrieve the top element first and then push it back. Therefore we must write another function StackTop() to access the top most element.
Push(Stack,item);
Here is the algorithm that returns the topmost element of the stack.
Algorithm : StackTop
StackTop(Stack)
Here ‘Stack’ contains the base address of the array ‘Stack’.
- Step-1 : Check Stack is empty or not. If Stack is empty then flash an error message – Stack underflow and go to step-3; otherwise go to step-2
- Step-2 : Access the topmost value of the Stack as: Item = Stack[top] and return it.
- Step-3 : Exit
Here is the ‘C’ implementation of this algorithm.
Implementation : StackTop StackTop(int Stack[])
We can also write StackTopAndTest() function in order to consider the case when the stack is empty and we try to know top most element of the stack.
{
int item;
if (IsStackEmpty())
{
printf("\nStack Underflow. ");
exit(0);
}
item=Stack[top];
return (item);
}
Here is the function that implements this task.
StackTopAndTest(int Stack[], int *item, int *flag)
Traversing a Stack
{
int item;
if (IsStackEmpty())
{
*flag = 1;
return;
}
*flag = 0;
*item = Stack[top];
}
While traversing a stack we process each element of a stack exactly once.
Here is the algorithm that traverse a stack.
Algorithm : Traverse
Traverse(Stack)
Here ‘Stack’ contains the base address of the array ‘Stack’.
- Step-1 : Check Stack is empty or not. If Stack is empty then flash an error message – Stack underflow and go to step-6; otherwise go to step-2
- Step-2 : Initialize i=top
- Step-3 : Repeat through step-5 while (i>=0)
- Step-4 : Access the value stored at ith position as: tem = Stack[i]
- Step-5 : Decrement the value of ‘i’ as i=i-1
- Step-6 : Exit
Here is the ‘C’ implementation of this algorithm:
Implementation : TraverseTraverse(int Stack[])
{
int i;
if (IsStackEmpty())
{
printf("\nStack Underflow. ");
return;
}
for(i=top; i>=0; i--)
printf("\n%d",Stack[i]);
}
Linked List Implementation of Stacks
We have already studied – array implementation of a stack. Since an array is a static data structure, so when a stack uses an array, it automatically inherits this static image of array. Therefore there is always a limit while we are inserting new elements. So in that implementation we have to declare how many elements can be inserted into the stack? This limitation is overcome by implementing a stack using a linked list.
The operation of inserting a new element as a first node is quite similar to that of pushing an element onto a stack. Similarly the deletion of a first element is similar to that of popping an element from a stack. Therefore a linked list can also represent a stack and such a stack is known as a linked stack.
While studying a singly linked list, we have used the header (a pointer variable) ‘first’ for a linked list which contains either a NULL value (if the list is empty) or the address of first node of the list. While implementing a stack using linked list we call this header as a ‘top’ pointer variable, which contains either a NULL (if stack is empty) or address of topmost node.
Declaration of a Stack Node
Like linked list, each element contains not only the item of information but also a pointer to the next element in the linked stack. The node of a linked stack is defined as:
struct StackNode
Initially the value of ‘top’ is set to NULL as:
{
int data;
struct StackNode *link;
};
typedef struct StackNode StackNode;
and the ‘top’ pointer variable is declared as:
StackNode *top;
top = NULL;
Like linked list, we can easily find the end of a linked stack. Since each node contains a pointer to the next node, the link field of last node contains a special value NULL. So we can easily go through one node to next until it encounters a NULL value.
Figure-4 shows a stack implementation as a linked list. This linked stack consists of four nodes. In a linked stack there is no limitation on number of elements. Now let us see various operation performed on a linked stack.
Figure 4
Initializing an Empty Stack
The InitializeStack() function is used to initialize a stack to empty before it is first used in a program. A stack is initialized by assigning a value NULL to ‘top’ pointer variable. Here is the function that implements this task.
InitializeStack(StackNode **top)
{
(*top)=NULL;
}
Is Stack Full or Not
Since a linked stack is implemented by using a linked list which can expand and shrink according to the situation. So as far as the memory space is available there is no need to worry about the number of elements to be inserted. However if there is no enough memory space then it is not possible to insert a new element. In such case, the function should return a value 1; otherwise 0.
This task is implemented as:
IsStackFull(StackNode *t)
/* This function returns 1, if the linked stack is full; otherwise return 0 */
{
if (t==NULL)
return 1;
else
return 0;
}
Is Stack Empty or Not
The linked stack is said to be empty only when the value of ‘top’ variable contains a NULL value. If it contains a NULL value then it returns a value 1; otherwise a value 0 is returned. Here is the function that implements this task.
IsStackEmpty(StackNode *t)
/* This function returns 1, if the linked stack is empty; otherwise return 0 */
{
if (t==NULL)
return 1;
else
return 0;
}
Popping a Node
It is equally simple to pop a node from a linked stack. In popping the stack we will firstly check whether the stack is empty or not. If the stack is empty then it displays an error message and the control is returned back. If the stack is not empty then we store the value ‘top’ variable in a temporary pointer variable ‘temp’, update the value of top and free the memory space occupied by the pointer variable ‘temp’.
Here is the algorithm, which pops a node from a non-empty linked stack.
Algorithm : PopNode
PopNode(&top)
Here ‘top’ is address of topmost node of the linked stack. Parameter ‘top’ is passed by reference (pointer to pointer) to allow it to change during insertion into an empty linked stack.
- Step-1 : Check whether the stack is empty of not. If the stack is empty then flash an error messag “Stack is Underflow” and go to step-6; otherwise go to step-2
- Step-2 : Store value of topmost node in a temporary, Pointer variable ‘temp’ as temp = (*top);
- Step-3 : Access the data field of ‘temp’ node as item = temp->data
- Step-4 : Update the value of ‘top’ as (*top) = (*top)->link;
- Step-5 : Free the memory space occupied by the temp node as freenode(temp);
- Step-6 : Exit
Here is the function that implements this task:
Implementation : PopNodePopNode(StackNode **top)
Like PopAndTest(), PopNode() must also consider the situation where item was not popped from stack successfully due to its underflow condition. So I leave the implementation of PopNodeAndTest() as an exercise for the students.
{
StackNode *temp;
int item;
if (IsStackEmpty(*top))
{
printf("\nStack Underflow");
exit(0);
}
temp=(*top);
item=temp->data;
(*top)=(*top)->link;
freenode(temp);
return (item);
}
Pushing a Node
When we push (insert) a node onto a stack, we pass the address of ‘top’ pointer variable and the value of ‘item’. The value of top is either a NULL or address of topmost node and ‘item’ is the item of information we want to push onto a stack. To achieve this we will firstly create a new node and then insert at the top position of the linked stack.
Here is the algorithm that pushes a node into a linked stack.
Algorithm : PushNode
PushNode(&top, int item)
Here ‘top’ is address of topmost node of the linked stack and ‘item’ be the item to be pushed into the stack. Parameter ‘top’ is passed by reference (pointer to pointer) to allow it to change during insertion into a linked stack and ‘item’ is passed by value.
Step-1 : Create a new node ‘temp’
Step-2 : Set the data field of ‘temp node to item as
temp->data = item
Step-3 : Store the value of ‘top’ variable in the link field of new node as temp->link = (*top)
Step-4 : Update the value of ‘top’
Step-5 : Exit
Here is the ‘C’ implementation of this algorithm.
Implementation : PushNode
PushNode(StackNode **top, int item)
Accessing Top Element of Stack
{
StackNode *temp;
temp = getnode();
temp->data=item;
temp->link=(*top);
(*top)=temp;
}
We can also access the top element of the linked stack without removing it from the stack. Here we will also consider the situation whether the stack is empty or not. If the stack is empty then we can not access the top element of it.
Here is the algorithm that implements this task.
Algorithm : StackTopNode
StackTopNodee(top)
Here ‘top’ is value of topmost node of the linked stack.
- Step-1 : Check whether the stack is empty of not. If the stack is empty then flash an error messa ge “Stack is Underflow” and go to step-6; otherwise go to step-2
- Step-2 : Store value of topmost node in a temporary. Pointer variable ‘temp’ as temp = (*top);
- Step-3 : Access the data field of ‘temp’ node as
- item = temp->data and return it.
- Step-4 : Exit
The ‘C’ implementation of this function is as:
Implementation : StackTopNodeStackTopNode(StackNode *top)
{
int item;
if (IsStackEmpty(top))
{
printf("\nStack Underflow");
exit(0);
}
item=top->data;
return (item);
}
I leave the implementation of StackTopNodeAndTest() for the student.
Traversing a Linked Stack
While traversing a linked stack we process each element of a stack exactly once.
Here is the algorithm that traverses a linked stack.
Algorithm : Traverse
Traverse(top)
Here ‘top’ is address of topmost node of the linked stack. Parameter ‘top’ is passed by value.
- Step-1 : Check whether the stack is empty of not. If the stack is empty then flash an error message “Stack is Underflow” and go to step-5;otherwise go to step-2
- Step-2 : Repeat through step- while (top != NULL)
- Step-3 : Access the data field of ‘top’ node as
- item = top->data
- Step-4 : Update the value of ‘top’ as top = top->link;
- Step-5 : Exit
Here is the function that implements this task:
Implementation : Traverse
Here is the ‘C’ implementation of this algorithm:Traverse(StackNode *top)
{
if (IsStackEmpty(top))
{
printf("\nStack is empty. ");
return;
}
while (top!=NULL)
{
printf("\n%d",top->data);
top=top->link;
}
}
Disposing a Linked Stack
As stated earlier a linked stack is a collection of dynamically allocated nodes. Therefore we must free the memory occupied by these nodes, if not in use.
Here is the algorithm which disposes a linked list.
Algorithm : DisposeStack
DisposeStack(&top)
Here ‘top’ is address of topmost node of the linked stack. Parameter ‘top’ is passed by reference (pointer to pointer) to allow it to change during its disposal of stack nodes.
- Step-1 : Store value of topmost node in a temporary
- pointer variable ‘current’ as current = (*top)
- Step-2 : Repeat through step-5 while (current != NULL)
- Step-3 : Update the value of ‘current’ as:
- current = current->link;
- Step-4 : Free the memory space occupied by the temp node as freenode(*top);
- Step-5 : Set (*top) = current
- Step-6 : Exit
Here is the ‘C’ implementation of this algorithm:
Implementation : DisposeStackDisposeStack(StackNode **top)
{
StackNode *current;
current = (*top);
while (current != NULL)
{
current = current->link;
freenode(*top);
(*top) = current;
}
}
Applications of Stacks
In this section we will study some applications of stacks.
Stack Frames for Subprograms/Functions
Stacks are more commonly used within the computer system when functions are called. When a function is called within another function then the system should remember the location from where the call was made, so that it can return thereafter the called function is completed. Here it is also needed to remember the parameters and local variables of the calling function so that their values will not be lost while its execution resumes.
Suppose that we have four functions first(), second(), third() and forth() and suppose that first calls second, second calls third and third calls forth. The execution of third will not have completed until forth has finished and return. Similarly the execution of second will not have completed until third has finished and return. In the same fashion, the execution of first will not have completed until second has finished and return.
Similar process takes place when a program uses recursion. In recursion whenever a function call is made, it is necessary to save the current values of parameters, local variables, and the return address of each successive call.
Now let us see another practical application of stacks – evaluation of arithmetic expression.
Evaluation of Arithmetic Expressions
Let we have an arithmetic expression as:
A+B*C
here A, B and C are one letter operands and ‘+’ and ‘*’ are operators. You can also have any legal variable name or constant in a programming language. The value of these operands must be consistent with the operations performed on them. As far as the operators are concerned, the ‘C’ language provides five basic arithmetic operators: plus(+), minus (-), multiply (*), divide (/) and modulus (%). However some other languages may also have an exponential (**) operation.
In a simple expression, such as
A+B
there occurs no problem with understanding the meaning of operation. The problem comes when an expression an expression has two or more than two operators as:
A+B*C
here the system faces a problem in deciding the order of the execution of the operators. It means that either addition operation is performed first and then multiplication or multiplication operation is performed first and then addition. To overcome this problem, the compiler sets a priority level for each arithmetic operator as shown in table-1.
Operators Priority
* 2
/ 2
% 2
+ 1
- 1
Therefore while evaluating the expression
A+B*C
The multiplication operation (B*C) is carried out first and then its result is added to A. Let we have an expression where two adjacent operators have the same priority, such as A/B*C then generally the operators are evaluated left to right, that is A/B is evaluated first and then its result is multiplied by C. But one should remember that parentheses can override these rules.
For example, in the expression (A+B)*C the expression A+B is evaluated first and then its result is multiplied with C. If we have nested parentheses as A*(B/(C+D)) then innermost parenthesized expression is evaluated first. But within parentheses, the same rule of precedence applies. It means that in following expression
A*(B+C/D)
The expression C/D is evaluated first, then addition is performed and finally the result is multiplied to A.
Generally when we write an expression, the operator is placed between its two operands (as we have seen so far). Such an expression is called as ‘infix’ expression and this notation is called as infix notation. Here are some examples of infix expressions:
A*B
A+B/C
(A+B)*(C-D)
A-B/(C*D)
The infix expressions are evaluated according to standard operator-precedence rule. Now the question arises-how can a compiler produce correct code of this infix expression? Actually when a compiler encounters an infix expression, it firstly translates this infix expression into a ‘postfix’ expression. In postfix expression the operator follows its two operands. In other words you can say that in postfix notation the operator is placed after its two operands. The process of writing the operators of an expression either before their operands or after them is called ‘Polish’ notations in honor of its discoverer, the Polish mathematician Jan Luksiewicz. When we convert an infix expression to a postfix expression we need to remember that highest precedence is converted first and then lower precedence.
Consider the following scenario in which a simple infix expression is converted into a postfix expression.
A+B*C Infix expression
A+(BC*) Converting the multiplication
A(BC*)+ Converting the addition
ABC*+ Postfix expression
Now let us see how to convert a bit complex ‘infix’ expression into a ‘postfix’ expression, such as:
A * B / C + D – E * F
Here firstly we will parenthesize this expression according to the operator priority precedence as:
( ( ( ( A * B ) / C ) + D ) – ( E * F ) )
Now we move all operators to their corresponding right parenthesize and in last we delete all parentheses.
Here the arrows head point to the right parenthesize of the corresponding operator. Therefore the resulting postfix expression is as….
A B * C / D + E F * -
Converting an Expression from Infix to Postfix
As stated earlier the expressions within innermost parenthesis must first be converted to postfix. So when we devise an algorithm we need to remember two things – firstly read the expression and parenthesize it correctly and secondly moves the operators to their right parentheses. Now let us see the function InfixToPostfix() that implements this task.
InfixToPostfix(char infix[], char postfix[])
{
int in=0,out=0,length;
char ch;
length=strlen(infix);
while (in < length)
{
if (infix[in]== ' ' || infix[in]=='\t')
{
in++;
continue;
}
else if (IsOperand(infix[in]))
{
postfix[out]=infix[in];
out++;
in++;
}
else if (infix[in]=='(')
{
Push(Stack,infix[in]);
in++;
}
else if (infix[in] == ')')
{
ch = pop(Stack);
while (ch != '(')
{
postfix[out]=ch;
out++;
ch=Pop(Stack);
}
in++;
}
else if (IsOperator(infix[in]))
{
if (IsStackEmpty())
Push(Stack,infix[in]);
else
{
ch=StackTop(Stack);
while ((top>-1)&&(GetPrec(ch)>=GetPrec(infix[in])))
{
postfix[out]=Pop(Stack);
ch=StackTop(Stack);
out++;
}
Push(Stack,infix[in]);
}
in++;
}
}
while (!IsStackEmpty())
{
postfix[out] = Pop(Stack);
out++;
}
postfix[out]='\0';
}
Here we have assumed that the stack holds character data items. In this function we have used three functions IsOpertor(), IsOperand() and getprec(). The IsOperator() is used to check whether the specified character is an operator or not. If not then it just displays an error message - Illegal Operator and the control is returned back; otherwise a value 1 is returned back.
Here is the function that implements this task.
IsOperator(char ch)
{
switch (ch)
{
case '*':
case '+':
case '-':
case '/':
case '%':
return 1;
default :
printf("\nIllegal Operator. ");
exit(0);
}}
The IsOperand() is used to check whether the specified character is an operand or not. If not then it returns 0; otherwise a value 1 is returned back. Here is the function that implements this task.
IsOperand(char ch)
{
if (isdigit(ch) || isalpha(ch))
return 1;
else
return 0;
}
The GetPrec() operator is used to return the precedence of the given character if it is an operator, otherwise it displays an error message - Illegal Operator. This function returns the value ‘2’ for multiplicative operators, ‘1’ for additive operators and –10 for left parentheses.
Here is the function that implements this task.
GetPrec (char op)
{
switch (op)
{
case '*':
case '/':
case '%':
return (2);
case '+':
case '-':
return (1);
case '(':
return (-10);
default :
printf("\nIllegal Operator. ");
exit(0);
}
}
Now let us see the behavior of this InfixToPostfix() function by considering the following expression
Thus the compiler firstly converts the infix expression into postfix expression and then during execution, the system evaluates this postfix expression by using a stack. Now let us see-how stack helps in evaluating a postfix expression.
Evaluating a Postfix Expression
When a postfix expression is evaluated then we must remember following main things-
- when an operand is encountered it is pushed onto stack.
- when an operator is encountered its operands will be the top two elements on the stack, thus two topmost operands are popped and the specified operator is used with these two popped operands and the result is pushed back onto the stack.
Let we have a postfix expression A B C * + Here the first character is an operand, so we push A, then B and in last C as: The next symbol is a operator (*) , therefore we pop B and C and perform the multiplication operator (*) as: Next symbol is +, so again we pop A and T1 and perform the addition operation as: Since there is no other symbol left, so T2 will contain the result.
T1 = B * C
And push T1 on stack as:
T2 = A + T1
And push T2 on stack as:
Now let us implement this task of evaluating the value of an arithmetic postfix expression.Evaluate(char postfix[])
Till now we have discussed infix expressions and postfix expression. We can also have another type of notation – prefix notation, in which the operator precedes its two operands. In other words we can say that in prefix notation the operator is placed before its two operands. Here also when we convert an infix expression into a prefix expression, we follow the precedence rule, that is highest precedence is converted first and then lower precedence.
{
int post=0,length,value,num;
int t1,t2;
char ch;
length=strlen(postfix);
while (post < length)
{
if (postfix[post]== ' ' || postfix[post]=='\t')
{
post++;
continue;
}
else if (isdigit(postfix[post]))
{
num=(int) (postfix[post]-'0');
Push(Stack,num);
}
else
{
t2=Pop(Stack);
t1=Pop(Stack);
switch (postfix[post])
{
case '+': value = t1+t2;
break;
case '-': value = t1-t2;
break;
case '*': value = t1*t2;
break;
case '/': value = t1/t2;
break;
case '%': value = t1%t2;
break;
default :
printf("\nIllegal operator.");
exit(0);
}
Push(Stack,value);
}
post++;
}
value=Pop(Stack);
return value;
}
Consider the following scenario in which a simple infix expression is converted into a prefix expression.
A+B*C Infix expression
A+(*BC) Converting the multiplication
+A(*BC) Converting the addition
+A*BC Prefix expression
However if we have a complex expression, such as:
A * B / C + D – E * F
then firstly we will parenthesize this expression according to the operator priority precedence as:
( ( ( ( A * B ) / C ) + D ) – ( E * F ) )
Now we move all operators to their corresponding left parenthesize and in last we delete all parentheses.
Here the arrows head point to the left parenthesize of the corresponding operator. Therefore the resulting prefix expression is as….
- + / * A B C D * E F
One should remember that the prefix form of a complex expression is not mirror image of a postfix expression. However as far as simple infix expression, such as A+B, A/B etc., it may be true, but not always.
Multiple Stacks
As stated earlier an array implementation of a stack suffers from a serious limitation of its static size. If the size is less then the stack full message announces much frequently. However if the size is large then it may result in wastage of memory space, if we use only a few number of memory locations. Some times we need to have several stacks in a programming environment. Therefore arrays may result in a lot of memory wastage.
To overcome this limitation to some extent we divide the same area space in several stacks as shown in figure-5. Figure-5(a) divides the same memory space into two arrays and figure-5(b) divides into five stacks.
Figure 5
Figure-5(a) represents two stacks of size 25 each and figure-5(b) represents five stacks of size 10 each. Here it is assumed that each stack occupies the same amount memory space. However you can also have different sizes of stacks. If you have different sizes of several stacks then there will be no efficient way to represent them sequentially (in array). Therefore in such cases we will use linked stacks.
A stack node for a linked stack is defined as:
struct StackNode
{
int data;
struct StackNode *link;
};
typedef struct StackNode StackNode;
Now if we want to represent ‘n’ number of stacks then we declare an array of pointers as:
StackNode *top[n];
here top[i] contains the address of the topmost node of ith stack, such that n > i ≥ 0. The process of initializing an ith stack is as:
top[i] = NULL;
Now let us discuss two basic operation on multiple stacks.
Pushing a Node in Multiple Stacks
When we push (insert) a new node then we need to mention the stack number, say ith stack and ‘item’ of information.
Here is the algorithm, which pushed a mode in multiple stacks.
Algorithm : PushNodes
PushNodes(i, item)
Here ‘item’ is pushed into the ‘i’th stack.
- Step-1 : Create a new node ‘temp’
- Step-2 : Set the data field of ‘temp node to item as
- temp->data = item
- Step-3 : Store the value of ‘top’ variable in the link field of new node as temp->link = top[i]
- Step-4 : Update the value of ‘top[i]’
- Step-5 : Exit
Here is the ‘C’ implementation of this algorithm.
Implementation : PushNodesPushNodes(int i, int item)
Popping a Node from Multiple Stacks
{
StackNode *temp;
temp = getnode();
temp->data = item;
temp->link = top[i];
top[i] = temp;
}
When we pop (delete) a node from multiple stacks then it is necessary to mention the stack number. Once we have a stack number we can easily pop topmost mode from this stack, only if it is not empty.
Here is the algorithm which pops topmost node from the given stack number.
Algorithm : PopNodes
PopNodes(i)
Here item is popped from ‘i’th stack.
- Step-1 : Check whether the stack is empty of not. If the stack is empty then flash an error message “Stack is Underflow” and go to step-6; otherwise go to step-2
- Step-2 : Store value of topmost node of ‘i’th stack in a temporary pointer variable ‘temp’ as temp = top[i]
- Step-3 : Access the data field of ‘temp’ node as item = temp->data
- Step-4 : Update the value of top[i]as top[i]=top[i]->link
- Step-5 : Free the memory space occupied by the temp node as freenode(temp);
- Step-6 : Exit
Here is the ‘C’ implementation of this algorithm.
Implementation : PopNodesPopNodes(int i)
In multiple stacks one must also consider the case that we have seen during the implementation of PopAndTest function. I leave the implementation of the remaining operations on multiple stacks as an exercise for the reader.
{
StackNode *temp;
int item;
if (IsStackEmpty(top[i]))
{
printf("\nStack Underflow");
exit(0);
}
temp = top[i];
item=temp->data;
top[i] = top[i]->link;
freenode(temp);
return (item);
}
Implementation of Stacks in C++
Like C, C++ provides two different ways to implement the stacks – either using arrays or using linked lists. Let us firstly study the implementation of stacks using an array.
Array Implementation of Stacks
When we implement the stack using an array we will define a class ‘Stack’ which contains data members and member function relating to the data structure ‘stack’. The structure of a class ‘Stack’ looks like this:
class Stack
{
private :
// data members
public :
// member functions
};
The data member part of the class ‘Stack’ consists of an array and a top variable as:
int st[Size];
int top;
Since st[] is an array, therefore it is necessary to declare its Size before its use as:
#define Size 10
In this class we will define all the member functions, such as:
IsStackFull()
Here the Pop() is overloaded in order to handle the function of PopAndTest. We have already defined the behavior of these functions in earlier section of array implementation of stacks in C. In C++ we will also take the advantage of constructor while initializing the value of ‘top’ variable, instead of defining another function InitializeStack(). The Stack() constructor is used to initialize a stack to an empty stack before it is firstly used in a program.
IsStackEmpty()
Push(int)
int Pop()
void Pop(int &, int &)
void StackTop(int &, int &)
Now the body of a class ‘Stack’ may looks like this:
class Stack
All these member functions are defined either inside a class or outside a class using a scope resolution operator (::) as:
{
private :
int st[Size];
int top;
public :
Stack();
int IsStackFull();
int IsStackEmpty();
void Push(int);
int Pop();
void Pop(int &, int &)
void StackTop(int &, int &);
};
Stack() is a constructor that initializes a newly created stack to an empty stack.
Stack :: Stack()
{
top=-1;
}
IsStackFull() determines if a stack is full.
int Stack :: IsStackFull()
{
if (top==Size-1)
return 1;
else
return 0;
}
IsStackEmpty() determines if a stack is empty.
int Stack :: IsStackEmpty()
Push(item) pushes an item onto the stack, only if the stack is not full.
{
if (top==-1)
return 1;
else
return 0;
}
void Stack :: Push(int item)
{
if (IsStackFull())
{
cout << "\nStack Overflow";
exit(0);
}
top++;
st[top]=item;
}
Pop() pops an item from the stack, only if the stack is not empty.
int Stack :: Pop()
Pop(int &, int &) pops an item from the stack, only if the stack is not empty; otherwise it indicates the calling function by setting the flag. If the flag is set (1) then it means that the stack is empty; otherwise not.
{
int item;
if (IsStackEmpty())
{
cout << "\nStack Underflow. ";
exit(0);
}
item=st[top];
top--;
return (item);
}
void Stack :: Pop(int &item, int &flag)
{
if (IsStackEmpty())
{
flag=1;
return;
}
flag=0;
item=st[top];
top--;
}
StackTop(int ,& int &) returns the top element of the stack, only if the stack is not empty.
void Stack :: StackTop(int &item, int &flag)
{
if (IsStackEmpty())
{
flag=1;
return;
}
flag=0;
item=st[top];
}
Linked List Implementation of Stacks
On similar track we will implement a stack in C++ using a linked list. When we implement a linked stack we define the node of a linked stack first as:
struct StackNode
The class ‘LinkedStack’ is defined as:
{
int data;
StackNode *link;
};
class LinkedStack
{
private :
StackNode *top;
public :
LinkedStack();
int IsStackFull(StackNode *)
int IsStackEmpty()
void PushNode(int);
int PopNode();
void PopNode(int &, int &);
void StackTopNode(int &, int &);
void display();
~LinkedStack();
};
The LinkedStack() constructor is used to initialize the value of ‘top’ pointer variable. The value of ‘top’ is asigned to NULL value and ~LinkedStack() destructor is used to free the memory occupied by all the nodes of linked stack. We can define these member functions either inside the class body or outside the class body. Let us see the definition of the member functions defined outside the class body.
LinkedStack() is constructor that initializes a newly created stack to the empty stack.
LinkedStack :: LinkedStack()
{
top=NULL;
}
~LinkedStack() is the destructor that traverses the nodes of a linked stack, freeing them one by one.
LinkedStack :: ~LinkedStack()
IsStackFull() determines whether there is sufficient memory space for dynamically created node.
{
SatckNode *current;
while (top != NULL)
{
current = top->link;
delete top;
top = current;
}
}
int LinkedStack :: IsStackFull(StackNode *t)
{
if (t==NULL)
return 1;
else
return 0;
}
IsStackEmpty() determines if the linked stack is empty.
int LinkedStack :: IsStackEmpty()
PushNode() inserts a new node at the top of the stack.
{
if (top == NULL)
return 1;
else
return 0;
}
void LinkedStack :: PushNode(int item)
PopNode() removes the top node of the linked stack, if the linked stack is not empty.
{
StackNode *temp;
temp = new StackNode;
temp->data = item;
temp->link = top;
top = temp;
}
int LinkedStack :: PopNode()
PopNode(int &, int &) removes the top node of the linked stack, if the linked stack is not empty; otherwise indicate the calling function by setting the flag.
{
StackNode *temp
if (IsStackEmpty())
{
cout << "\nStack Underflow";
exit(0);
}
int item=top->data;
temp = top;
top = top->link;
delete temp;
return item;
}
void LinkedStack :: PopNode(int &item, int &flag)
{
StackNode *temp
if (IsStackEmpty())
{
cout << "\nStack Underflow";
flag=1;
return;
}
flag=0;
item=top->data;
temp = top;
top = top->link;
delete temp;
}
StackTopNode()retrieves the top node of the linked stack, if the linked stack is not empty.
void LinkedStack :: StackTopNode(int &item, int &flag)
Stack in C++ using Templates
{
if (IsStackEmpty())
{
flag=1;
return;
}
flag=0;
item=top->data;
}
Till now the purpose of defining a stack in C and C++ looks alike. In these implementations, we have created only a single stack of type int. What will you do if you need two stacks of different types, say one stack of type ‘int’ and one for ‘char’. In that case you must declare two stacks separately. In each type of stack we need to define separate set of primitive operations, such as Push(), Pop(), etc. To overcome this limitation there is no provision in ‘C’, but fortunately C++ provides the concept of ‘templates’.
We know that templates come in two flavors – function templates and class templates. Let us see the use of class templates in defining a stack. When templates are used in conjunction with classes, they bind the type of the class to the class itself until a class of a particular type is actually created. This process of creation of a class of a particular type is called instantiation.
A class template starts with the following statement
template
here ‘T’ is any built-in data type or user-defined data type. For the sake of convenience we will consider only the built-in data type. Of course you may use user-defined data type but for that case you have to explicitly modify some operations.
The class ‘Stack’ is now defined as:
template
class Stack
{
private :
T St[Size];
int top;
public :
Stack();
int IsStackFull();
int IsStackEmpty();
void Push(T item);
T Pop();
void Pop(T &, int &);
void StackTop(T &, int &);
};
Now if you define these member functions outside the class body then it is necessary to prefix the following statement template to every member function of the class Stack as:
template Stack :: Stack()
Now if we want to instantiate one stack of type ‘int’ and one of type ‘char’ then we use the following statements:
{
top=-1;
}
template int Stack :: IsStackFull()
{
if (top==Size-1)
return 1;
else
return 0;
}
template int Stack ::IsStackEmpty()
{
if (top==-1)
return 1;
else
return 0;
}
template void Stack :: Push(T item)
{
if (IsStackFull())
{
cout << "\nStack Overflow. ";
exit(0);
}
top++;
St[top]=item;
}
template T Stack :: Pop()
{
T item;
if (IsStackEmpty())
{
cout << "\nStack Underflow. ";
exit(0);
}
item = St[top];
top--;
return item;
}
template void Stack :: Pop(T &item, int &flag)
{
if (IsStackEmpty())
{
flag=1;
return;
}
flag=0;
item = St[top];
top--;
}
template void Stack :: StackTop(T &item, int &flag)
{
if (IsStackEmpty())
{
flag=1;
return;
}
flag = 0;
item = St[top];
}
Stack IStk;
Stack CStk;
As I mentioned earlier, one set of routines for a template class Stack is sufficient to manipulate a stack of any type.
A stack is a collection of elements in which all insertions and deletion are made at one end, called the top of the stack. The stack is also called as Last-In First-Out data structures. Typical operations that can be performed on stack are – push and pop. In C/C++ stacks can be implemented either by using arrays or linked lists. One must handle overflow and underflow conditions if stacks are implemented as arrays.
Stacks are more frequently used in functions calls and evaluation of an infix expression. typically an infix expression is converted into a postfix expression and then postfix expression is evaluated using stacks.
Constructor and Destructor is very important basic concepts of C++. Whenever we create an object, there are two special types of functions that would be created automatically if we have not written them in the program. They are known as Constructor and Destructor.
Now Let us get the basic concepts of constructor and destructor.
Constructor:-
As its name is indicating, Constructor means "which constructs something" . We will see what it is going to construct..
Definition:-
Constructor is a special member function with the same name as its class.
Syntax :-
1. class_name(){ definition }
2. class_name(argument1, argument2,...){ definition }
We are going to write a constructor example to understand concept better.
Example:
class Person
{
int age;
int weight;
int height;
public:
Person() // constructor for class Person - same name as class , no return type
{
age = 20;
weight = 60;
height = 160;
}
void showData(); //other function
void enterData(); //other function
};
Can you guess what constructor is doing in above program? If your answer is initialization. then you are absolutely correct. The main responsibility of constructor is to initialize the data members of the class.
But above constructor is having one restriction, it will initialize same values to all the objects. It is not what we want.We should be able to provide different data values to every person. Every person has different body setup.
So we need to provide different values. How to do it? It is very simple. Add one more constructor. Having more than one constructor is called constructor overloading.
Hence this is also an example of constructor overloading.
class Person
{
int age;
int weight;
int height;
public:
Person() // constructor for class Person - same name as class , no return type
{
age = 20;
weight = 60;
height = 160;
}
Person(int a,int w,int h) // added new constructor can accept different values
{
age = a;
weight = w;
height = h;
}
void showData(); //other function
void enterData(); //other function
};
NOTE :- You can write Constructor definition outside the Class as you do normally with other function.
Example:
class Person
{
int age;
int weight;
int height;
public:
Person(); // constructor for class Person - same name as class , no return type
void showData(); //other function
void enterData(); //other function
};
Person::Person() // outside of the class
{
age = 20;
weight = 60;
height = 160;
}
Use:-
Constructors are used to create, and can initialize, objects of their class type.
Call:-
When an object of a class is created, constructor for that class is called.If there is no constructor defined, DEFAULT constructor is invoked. But default constructor doesn't initialize any variable.
Some facts about Constructors :
* Constructors are special member functions with the same name as the class.
* Constructors can not return any value (nothing even void) .
* Constructors are intended to initialize the members of the class when an instance of that class is created.
* Constructors are not called directly.
* Constructors can not be virtual.
* Constructors can not be static.
* Constructors can not be const.
* Constructors can not be volatile.
* Constructors aren't automatically inherited between base and derived classes.
* There can be any number of constructors in a same class.
* They must have different parameters to distinguish them. (=> Constructors can be overloaded )
Destructors :-
Destructors are opposite of Constructors.They are called when objects are destructed. They can be used to release memory occupied by the objects.
Definition :
Destructors in C++ also have the same name, but they are preceded by a '~' operator.For example destructor for Person class will be declared as ~Person().
Syntax:
~class_name(){}
Example :
class Person {
public:
// Constructor for class Person
Person();
// Destructor for class Person
~Person();
};
Use :-
Destructors are usually used to release memory and do other cleanup for a class object and its class members when the object is destroyed.
Call:-
The destructors are called when the object of a class goes out of scope or is explicitly deleted.
Some facts about Destructors:
* If the constructor/destructor is declared as private, then the class cannot be instantiated.
* It is not necessary to declare a constructor or a destructor inside a class. If not declared, the compiler will automatically create a default one for each.
* A destructor takes no arguments and has no return type.
* Its address cannot be taken.
* Destructors cannot be declared const.
* Destructors cannot be declared volatile.
* A destructor can be declared virtual or pure virtual.
* We don't have to call destructor explicitly, it is called automatically.
* Only one destructor can be there for each object.
I hope you have understood basic concepts of Constructors and Destructors in C++. Please don't forget to send your valuable feedback.
Control Structures
Normally the statements in a program, are executed sequentially one by one. This is known as the normal flow of control. One of the keys to designing intelligent programs is to make them able to make decisions, such as whether you are going to see a movie or not, whether to play a cricket match or not, whether you want to go on a long journey, and if so by the train or by the air.
Like these activities programs also need to decide among alternative actions, such as whether the year is a leap or not, whether the number is even or odd, and so on. Thus there is the possibility of changing the sequence of statements, based on these decisions.
Decisions can be made in C++ in several ways. C++ provides the if statement and the switch statement for implementing these decisions. The former one is generally used to choose between two alternatives, whereas the later one for multiple alternatives. In this article we will discuss these two decision making statements, along with logical and relational operators, and in last we will see the conditional operator which provides another way to make a choice.
The if statement
The if statement is used in a program where you need to perform a particular action on some condition. If the result of this condition is true then perform the action; otherwise either perform some other action or not. The if statement comes in two flavors:
the if statement
the if–else statement
The if statement is the simplest form of the decision statements. The if statement causes a program to execute a statement or a set of statements when a test-condition results in true, and to skip that statement or set of statements when the condition is false.
The C++ uses the keyword if to implement the decision control statement. The general form of the if statement is:
if (test-condition)
statement;
here if is the keyword, followed by a test-condition. The test-condition must always be enclosed within a pair of parentheses. If this test-condition is true then the statement is executed; otherwise the statement is not executed and skipped by the program. Now we will see how the test-condition is expressed in C++?
Like C, C++ provides six relational operators as shown in Fiigure 1. The relational operators compare two numbers to check whether they are equal, unequal or whether one is greater than other, and so on. Each relational expression results in 1 if the comparison is true and 0 if the comparison is false.
Let we have x = 10 and y = 6 then
x == y results in 0
x != y results in 1
x > y results in 1
x < y results in 0
x >= y results in 1
x <= y results in 0
Figure 1
Here the first number, which is on the left-hand side of the relational operator, is compared with the number, which is on the right hand side. Note that the relational operators have a lower precedence than the arithmetic operators. Thus the following expression
x – 6 > y + 2
corresponds to
(x - 6) > (y + 2)
and not the following
x – (6 > y) + 2
Therefore if x = 10 and y = 6 then the result of the relational expressions are as:
Relational expression Result
x – 6 > y +2 0
x – 6 < y +2 1
x – 6 == y +2 0
x – 6 != y +2 1
x – 6 >= y +2 0
x – 6 <= y +2 1
Here is a simple program which illustrates the use of the if statement and the relational operators.
// Program-con1.cpp
#include
void main()
{
int num;
cout << “\nEnter a number : ”;
cin >> num;
if (num >= 0)
cout << “You have entered a positive number.”;
}
Here is the output of this program
Enter a number : 2
You have entered a positive number.
Let us see another example that makes you comfortable with the simple if statement. While purchasing some shirts, a discount of 20% offered if the number of shirts purchased is more than 5. It is required to calculate the cost of shirts, if quantity and cost per shirt are entered through the keyboard.
// Program-con2.cpp
#include
void main()
{
int qty;
float tprice, price, discount;
discount = 0.0;
cout << “\nEnter number of shirts : ”;
cin >> qty;
cout << “Enter price per shirt : ”;
cin >> price;
if (qty > 5)
discount = 0.2;
tprice = qty * price * (1-discount);
cout << “Total price : ” << tprice;
}
In this program, the discount is set to 0 initially. After this we read the quantity and the price per shirt. The next statement sets discount to 0.2, only if the quantity is greater than 5. After the if statement, the total price is evaluated.
Here is some sample outputs of this program
Enter number of shirts : 4
Enter price per shirt : 125.50
Total price : 502
Enter number of shirts : 8
Enter price per shirt : 160.0
Total price : 1024
In the first output, the test-condition results in false, since 4 is not greater than 5. Thus the discount remains 0. On the other hand, in the second output, the test condition results in true, since 8 is greater than 5. Therefore the discount is set to 0.2 and the total price is evaluated using this new value of discount.
Multiple Statements in the if Body
You can also have more than one statement in an if body. In such case, it is necessary to enclose them within a pair of braces. The general form of such an if statement is as:
if (test-condition)
{
statement1;
statement2;
statement3;
statement4;
}
Following program illustrates this.
// Program-con3.cpp
#include
void main()
{
int age;
cout << “\nEnter your age : ”;
cin >> age;
if (age >= 20)
{
cout << “You have grown up.”;
cout << “\nNow you can take a pepsi.”;
}
}
The output of this program is
Enter your age : 24
You have grown up.
Now you can take a pepsi.
If you don’t use a pair of braces then the C++ compiler assumes that you have only one statements in the if body and executes this one statement only after the successful evaluation of the test-condition.
Figure 2(a) shows the typical operation of the if statement.
The if–else Statement
In earlier if statement, it decides whether a particular statement or a set of statements should be executed or not depends on the result of test-condition. It does nothing when the test-condition is false. The if–else statement allows you to execute a statement or a set of statements when the test-condition is true and another statement or a set of statements when the test-condition is false.
The general form of an if–else statement is
if (test-condition)
statement1;
else
statement2;
If the result of test-condition is true, the statement1 is executed and statement2 is skipped. If the result of test-condition is false, the statement2 is executed and statement1 is skipped.
Like simple if statement, if you have multiple statements in if body and as well as in else body then it is necessary to enclose them within a pair of braces as:
if (test-condition)
{
statement1;
statement2;
statement3;
statement4;
}
else
{
statement5;
statement6;
statement7;
statement8;
}
Figure 2
Here if test-condition is true, the program executes statement1, statement2, statement3, and statement4 and skips over else body statements. If the test-condition is false, the program executes statement5, statement6, statement7, and statement8 and skips if body statements. Figure 2(b) shows the behavior of the if–else statement.
Now let us see a simple program that finds out the largest number among two numbers.
// Program-con4.cpp
#include
void main()
{
int a, b;
cout << “\nEnter first number : ”;
cin >> a;
cout << “Enter second number : ”;
cin >> b;
if (a>b)
cout << “First number is greater than second number.”;
else
cout << “Second number is greater than or equal to first number.”;
}
Here is some sample output
Enter first number : 10
Enter second number : 8
First number is greater than second number.
Enter first number : 8
Enter second number : 10
Second number is greater than or equal to first number.
Note that C++ is a free-form language. You can write if and else anywhere. For the sake of clarity we write the else exactly below the if and the statements in the if body and else body have been shifted to right just for indentation.
Nested if–else Statement
The C++ provides the facility of using an entire if–else statement within either the body of the if statement or the body of an else statement. This is called as nested if–else statement.
Program con5.cpp illustrates this concept.
// Program con5.cpp
#include
void main()
{
int a,b;
cout << “\nEnter first number : ”;
cin >> a;
cout << “Enter second number : ”;
cin >> b;
if (a>b)
cout << “First number is greater than second number.”;
else
{
if (a cout << “Second number is greater than first number.”;
else
cout << “Both numbers are equal.”;
}
}
Here are some sample output
First Run
Enter first number : 10
Enter second number : 12
Second number is greater than first number.
Second Run
Enter first number : 12
Enter second number : 2
First number is greater than second number.
Third Run
Enter first number : 7
Enter second number : 7
Both numbers are equal.
In this program, the second if–else statement is nested in the first else statement. If the first test-condition, that is a>b, is true then it displays the message
First number is greater than second number.
If the first test-condition is false, then the second test-condition, that is a
Second number is greater than first number.
Otherwise it displays the message
Both numbers are equal.
Here an if–statement is placed within the else body of the if–else statement. You can also place an if–else in the if block as well. Note that there is no limit on how deeply the ifs and the elses can be nested. If you are nested more deeply then you should make proper indentation; otherwise it may misguide you and others. In such case you may inadvertently match the wrong if. Following program shows this.
// Program con6.cpp
#include
void main()
{
int age;
cout << “\n Enter your age : ”;
cin >> age;
if (age <=5)
cout << “\n You are a lovely kid.”;
else
if (age <= 10)
cout << “\n You are grwoing up.”;
else
if (age <= 20)
cout << “\n You have not yet grown up.”;
else
if (age <= 30)
cout << “\n Now you have grown up.”;
else
cout << “\n You are a nice gentleman.”;
}
No doubt, this program would work. But when you will look at this program after some time, you may get confused because the else is matched with the wrong if. Here is the proper indentation of this program.
// Program con7.cpp
#include
void main()
{
int age;
cout << “\n Enter your age : ”;
cin >> age;
if (age <=5)
cout << “\n You are a lovely kid.”;
else
if (age <= 10)
cout << “\n You are growing up.”;
else
if (age <= 20)
cout << “\n You have not yet grown up.”;
else
if (age <= 30)
cout << “\n Now you have grown up.”;
else
cout << “\n You are a nice gentleman.”;
}
Here are some sample outputs of this program
First Run
Enter your age : 20
You have not yet grown up.
Second Run
Enter your age : 40
You are a nice gentleman.
Third Run
Enter your age : 10
You are growing up.
Fourth Run
Enter your age : 4
You are a lovely kid.
Since we know that C++ is a free-form language, therefore you can also rearrange the earlier program into an easy–to–read format as shown in program con8.cpp.
// Program con8.cpp
#include
void main()
{
int age;
cout << “\n Enter your age : ”;
cin >> age;
if (age <=5)
cout << “You are a lovely kid.”;
else if (age <= 10)
cout << “You are grwoing up.”;
else if (age <= 20)
cout << “You have not yet grown up.”;
else if (age <= 30)
cout << “Now you have grown up.”;
else
cout << “You are a nice gentleman.”;
}
This revised format is much clearer than earlier one. You may think that the else–if is a new keyword, but unfortunately it is not true. It is still one if–else statement contained within another one. This entire structure still counts as one statement and lets you choose one among several alternatives.
Logical Operators
Logical operators allow you logically combine two or more than two conditions into one condition. For example, let you want to find out a number whose value is greater than 100 but less than 1000. Or if you want to check whether you have entered a character whose value must be greater than or equal to ‘0’ and less than or equal to ‘9’.
C++ provides three logical operators as shown in Figure 3
Figure 3
The first two operators, && and ||, are used to combine two conditions in one condition. The third operator,!, negates, or reverse the truth-value of the expression following it. The precedence of logical operators is lower than the relational operators.
Logical AND Operator: &&
The logical AND operator (&&) is used to combine two expressions into one. If the result of both expressions are true then the result of complete resulting expression is true. If either or both are false then resulting expression would be false.
In program con7.cpp, we have used nested if–elses you have to very careful to match the corresponding ifs and elses. This limitation is overcome by the logical AND operator as:
// Program con9.cpp
#include
void main()
{
int age;
cout << “\n Enter your age : ”;
cin >> age;
if (age <=5)
cout << “\n You are a lovely kid.”;
if (age >5 && age <= 10)
cout << “\n You are growing up.”;
if (age > 10 && age <= 20)
cout << “\n You have not yet grown up.”;
if (age > 20 && age <= 30)
cout << “\n Now you have grown up.”;
if (age > 30)
cout << “\n You are a nice gentleman.”;
}
We have used the && operator as can be seen from the second if statement. The && operator lets you combine the two test expressions into one.
Here are a couple of sample runs.
First Run
Enter your age : 12
You have not yet grown up.
Second Run
Enter your age : 53
You are a nice gentleman.
Third Run
Enter your age : 27
Now you have grown up.
Fourth Run
Enter your age : 3
You are a lovely kid.
The logical OR Operator: ||
The OR operator also combines two expressions into one. The behavior of this OR operator is similar to the english word or. The resulting expression is true if either or both of the original expressions are true. The resulting expression is false if both of the logical expressions are false.
Let us summarize the behavior of OR operator using two expressions Expression1 and Expression2.
Expression1 Expression2 Result
True || True True
True || False True
False || True True
False || False False
Let us use the || operator in a program to check for both a lowercase letter and an uppercase first three letters.
// Program con10.cpp
#include
void main()
{
char ch;
cout << “\n Enter a character (a/b/c) : ”;
cin >> ch;
if (ch == ‘a’ || ch == ‘A’)
cout << “You have entered either a or A”;
else if (ch == ‘b’ || ch == ‘B’)
cout << “You have entered either b or B”;
else if (ch == ‘c’ || ch == ‘C’)
cout << “You have entered either c or C”;
else
cout << “Read your question again.”;
}
Here are the sample outputs of this program
First Run
Enter a character (a/b/c): b
You have entered either b or B
Second Run
Enter a character (a/b/c) : c
You have entered either c or C
Third Run
Enter a character (a/b/c): s
Read your question again.
Fourth Run
Enter a character (a\b\c): a
You have entered either a or A
The Logical NOT Operator: !
The logical NOT operator is a unary operator that takes only one expression. The NOT operator reverses the logical value of its expression. If the value of its operand is true then the ! operator makes it false; if it is false the ! operator makes it true.
Following expressions summarize the behavior of NOT operator
Expression Result
!True False
!False True
For example, in an expression (num == 10) the result is true if num is equal to 10; but in an expression ! (num == 10) the result is true if num is not equal to 10. Obviously you can achieve the same effect by using the relational operator – “not equal to” as: (num != 10).
But it does not mean that you can use a relational operator in place of a NOT operator. The NOT operator is very helpful with functions that return true-false values. The concept of this NOT operator will be clear later on.
You can also use && and || operators together in order to combine two or more expressions. Now let us write a program to determine whether the year is a leap or not.
// Program con11.cpp
#include
void main()
{
int year;
cout << “\nEnter a year : ”;
cin >> year;
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
cout << “Leap year.”;
else
cout << “Not a leap year.”;
}
Here are the sample outputs of this program
First Run
Enter a year : 1988
Leap year.
Second Run
Enter a year : 1900
Not a leap year.
We know that a year is a leap year if it is either divisible by 4 or not divisible by 100 or divisible by 400. Note that the logical AND operator has a higher precedence than the logical OR operator and both these logical operators have a lower precedence than relational operators. But the NOT (!) operator has a higher precedence than any of the relational or arithmetic operators.
Thus the expression
! num == 0 is interpreted as (!num) == 0 instead of ! (num == 0).
If you want the later interpretation then it is necessary to use parentheses as:
! (num == 0)
The Conditional Operator ? :
The conditional operator ? and : can often be used in place of a simple if–else statement. It is the only C++ operator that requires three operands, that’s why it is also called as ternary operator. The general form of this operator is
expression1 ? expression2 : expression3
Here if the expression1 is true then the value returned by the conditional expression will be expression2; otherwise the value returned will be expression3.
Let us write a simple program that finds the largest number among two numbers.
// Program con12.cpp
#include
void main()
{
int a, b, big;
cout << “\n Enter two numbers : ”;
cin >> a >> b;
big = (a > b) ? a : b;
cout << “Largest number : ” << big;
}
The output of this program is
Enter two numbers : 20 24
Largest number : 24
In this program, you have used the conditional operator in the following statement
big = (a > b) ? a : b;
The expression to the right side of the equal sign is called the conditional expression. The part of conditional expression, before the question mark ? is itself a test-expression. If this test-expression is true then the entire condition expression returns the value of the operand following the question mark; a in this program. If this test-expression is false then the entire condition expression returns the value of the operand following the colon; b in this program.
It produces the same result as the following if–else statement
if (a>b)
big = a;
else
big = b;
Naturally the former one is more concise than the later one.
While using conditional operators, one should remember that it is not necessary that the conditional operators should be used in arithmetical statements. You can also use conditional operators in simple statements.
Following program illustrates this fact.
// Program con13.cpp
#include
void main()
{
int num;
cout << “\nEnter a number : ”;
cin >> num;
(num >= 0 ? cout << “Positive number” : cout << “Negative number.”);
}
Here is the output of this program
Enter a number : 4
Positive number
Another main point to note is that the conditional operator can be nested, as illustrated in the following program.
// Program con14.cpp
#include
void main()
{
int a, b, c, big;
cout << “\nEnter three numbers : ”;
cin >> a >> b >> c;
big = (a>b ? (a>c ? a : c) : (b>c ? b : c));
cout << “Largest number : ” << big;
}
The output of this program is
Enter three numbers : 10 14 21
Largest number : 21
The only limitation of using a conditional operator is that you can use only one statement after the ? or after the colon(:).
The Mistake You Will Probably Not Like
You should always keep in mind the difference between the logical is-equal-to operator (==) and the arithmetic assignment (=) operator. The former operator is used to compare two numbers for its equality whereas the later operator is used to assign the value of the left-hand side.
X == 10 // Comparison
X = 10 // Assignment
Following program shows the difference between these two operators.
// Program con15.cpp
#include
void main()
{
int num;
cout << “\n Enter a number : ”;
cin >> num;
if (num == 10)
cout << “You have entered 10”;
else
cout << “You have not entered 10”;
if (num = 10)
cout << “\nYou have entered 10”;
else
cout << “\nYou have not entered 10”;
}
Here are the sample outputs of two runs.
First Run
Enter a number : 8
You have not entered 10
You have entered 10
Second Run
Enter a number : 10
You have entered 10
You have entered 10
The first if statement correctly displays the output whereas the second if statement displays
You have entered 10
irrespective of what you enter as the value of num. It is because, in second if statement you have used assignment operator whereas in first if statement you have used relational operator. That’s why in second if statement is reduced to
if(10)
each time you run the program. And a non-zero value is always a true value. Hence if (10) always evaluates to true and you would get the output - You have entered 10.
Another common mistake you probably make while using the if statement is to place a semicolon (;) after the test-condition. For instance
if (num == 10) ;
cout << “You have entered 10”;
Here if the test-condition is true, the null statement (;) gets executed followed by the statement that displays the message - You have entered 10. If the test-condition is false then it skips the null statement and executes the statement that displays the message - You have entered 10. Thus irrespective of the result of test-condition, the statement
cout << “You have entered 10”;
is bound to get executed every time.
The switch Statement
We know that the nested if–elses provides the facility of making a choice among several alternatives. The limitation of using nested if–elses is that you have to carefully match the corresponding ifs and elses and match the corresponding pair of braces. C++ provides another decision control statement, a switch statement, that allows you to handle such cases more effectively than a series of if–else statements.
The syntax of the switch statement is as:
switch (integer-expression)
{
case label1 :
statement(s);
case label2 :
statement(s);
case label3 :
statement(s);
….
case labeln :
statement(s);
default :
statement(s);
}
Here the integer expression must be any expression that yields an integer value. It could be any integer constant or an expression that reduces to an integer value. The values followed by the keyword case are labels. Each label must be an integer or a character constant. Also each label must be different from all the others.
When a program encounters a switch statement, the integer- expression is evaluated first and then the control is transferred to the line labeled with the value corresponding to the value of integer expression. After this, the statements following that case labels gets executed and all subsequent cases and default statements as well unless you explicitly direct it otherwise. If it does not find any match it executes the statements of default case.
Here is a simple program of a switch statement.
// Program con16.cpp
#include
void main()
{
int n;
cout << “\nEnter a number : ”;
cin >> n;
switch (n)
{
case 1:
cout << “\nYou entered 1.”;
case 2:
cout << “\nYou entered 2.”;
case 3:
cout << “\nYou entered 3.”;
case 4:
cout << “\nYou entered 4.”;
default :
cout << “\nYou have not entered 1, 2, 3 or 4.”;
}
}
The output of this program is
Enter a number : 3
You entered 3.
You entered 4.
You have not entered 1, 2, 3 or 4.
From this output it is clear that whenever it finds a match, it then sequentially executes all the statements following that line, including the default as well. If you do not want to execute all the subsequent cases and the default then use a break statement. The break statement skips the remaining statements of the switch statement and transfers the control to the statement following the switch statement.
Program switch17.cpp shows how to use switch and break statement together.
// Program con17.cpp
#include
void main()
{
int n;
cout << “\nEnter a number : ”;
cin >> n;
switch (n)
{
case 1:
cout << “You entered 1.”;
break;
case 2:
cout << “You entered 2.”;
break;
case 3:
cout << “You entered 3.”;
break;
case 4:
cout << “You entered 4.”;
break;
default :
cout << “You have not entered 1, 2, 3 or 4.”;
}
}
Now when you run this program, you get the following output
Enter a number : 3
You entered 3.
In this program, you have used a break statement at the end of each case section. The break statement terminates the entire switch statement and transfers the control to the first statement following the end of the switch statement.
In program con16.cpp and con17.cpp you have used case labels arranged in ascending order, that is 1, 2, 3, and so on. However it is not mandatory. You can also use case labels in any order you like. Following program illustrates this view.
// Program con18.cpp
#include
void main()
{
int n;
cout << “\n Enter a number : ”;
cin >> n;
switch (n)
{
case 4:
cout << “You entered 4.”;
break;
case 1:
cout << “You entered 1.”;
break;
case 27:
cout << “You entered 27.”;
break;
case 6:
cout << “You entered 6.”;
break;
default :
cout << “Pardon me.”;
}
}
Here are the sample outputs this program
First Run
Enter a number : 1
You have entered 1.
Second Run
Enter a number : 2
Pardon me.
The switch Statement with Character Variables
You can also use characters instead of integers as case labels, as shown in program switch4.cpp.
// Program con19.cpp
#include
void main()
{
char ch;
cout << “\nEnter any vowel : ”;
cin >> ch;
switch (ch)
{
case ‘a’:
cout << “You entered a.”;
break;
case ‘e’:
cout << “You entered e.”;
break;
case ‘i’:
cout << “You entered i.”;
break;
case ‘o’:
cout << “You entered o.”;
break;
case ‘u’:
cout << “You entered u.”;
break;
default :
cout << “You have not entered any vowel.”;
}
}
Here is the sample output of four runs.
First Run
Enter any vowel :e
You entered e.
Second Run
Enter any vowel :i
You entered i.
Third Run
Enter any vowel :s
You have not entered any vowel.
Fourth Run
Enter any vowel :a
You entered a.
In this program, you have used a character variable ch as the switch variable, and character constants as the case labels. You can also mix integer and character constants in different cases of a single switch statement.
// Program con20.cpp
#include
void main()
{
char ch;
cout << “\n Enter any vowel : ”;
cin >> ch;
switch (ch)
{
case ‘a’:
cout << “You entered a.”;
break;
case 101:
cout << “You entered e.”;
break;
case ‘i’:
cout << “You entered i.”;
break;
case 111:
cout << “You entered o.”;
break;
case ‘u’:
cout << “You entered u.”;
break;
default :
cout << “You have not entered any vowel.”;
}
}
The output of this program is similar to con19.cpp.
The switch statement also provides the facility of executing a set of statements for more than one case label. Following program illustrates this concept:
// Program con21.cpp
#include
void main ()
{
char ch;
cout << “\nEnter any of first four alphabet:”;
cin >> ch;
switch (ch)
{
case ‘a’:
case ‘A’:
cout << “You entered a and A”;
break;
case ‘b’:
case ‘B’:
cout << “You entered b and B”;
break;
case ‘c’:
case ‘C’:
cout << “You entered c and C”;
break;
case ‘d’:
case ‘D’:
cout << “You entered d and D”;
break;
default:
cout << “You have not entered any of the first four alphabet.”;
}
}
Since we know that whenever a switch statement finds a match. If then executes all the subsequent line in the switch unless it encounters a break statement. So if an alphabet ‘a’ is read through the keyboard. The case ‘a’ is satisfied and since there is no statement in this case label so the control is transferred to the next case ‘A’ and executes all the statements in this case.
Here is the output of this program
First Run
Enter any of first four alphabet: a
You entered a and A
Second Run
Enter any of first four alphabet: g
You have not entered any of the first four alphabet.
From this program of the switch statement, you might think that it is necessary to use the keyword default. But it is not true. If you don’t use a default case and the switch statement does not find a match then nothing gets executes within the switch statement and the control is transferred to the next statement, if any, following the control structure.
Switch versus if-else
One may asks you – Is switch a better replacement for if-else? We know that both the switch and the if-else statements allow us to select from several alternatives. Each of these two decision control statements has its own advantages. The if-else statement can handle ranges for instance, you can use the if-else statement as
if (num >100 && num <=200)
// statements
else if (num >200 && num <=500)
// statements
else
// statements
The switch can not handle these ranges, each switch case label must be a single value and that value must be an integer or a character. You can not use even a floating case label. So as far as the ranges or float point number are countered, you must use if-else statement, on the other hand, if the case label are integer constants (or character constant) then the switch statement is more efficient, easy to write and understand. Like if-else statement, you can also use a switch within another switch but in practice it is rarely used, such statement is called nested switch statement.
The goto statement
The goto statement is an unconditional control statement. It takes the control where you want. Although it is necessary to understand the goto statement but it is not a good idea to use this statement because such programs are unreliable, unreadable and hard to debug.
Consider the following program
// Program con22.cpp
#include
void main()
{
int number;
start :
cout << “\nEnter a number :”;
cin >> number;
if (number >=0)
{
cout << “Positive number”;
goto start;
}
else
cout << “You have entered a negative number”;
}
The output of this program is:
Enter a number =10
Positive number
Enter a number =20
Positive number
Enter a number = -5
You have entered a negative number.
In this program, the control is transferred to the label ‘start’ till the condition is satisfied. The label is terminated by a colon. The keyword goto, followed by this label name, then takes you to the label. However a good programmer should never use a goto statement in his/her program because there is almost never any need to use goto. You can achieve the same using some other more elegant decision Control and loop control statement.
Loops
The statements in programs, which we have seen so far, include either a sequential or decision control structure in which statements are executed exactly once. But in a general programming environment we need to perform an activity over and over, after with a little variation.
C++ provides loops that cause a part of your program to be repeated either a certain number of times or until a specific event occurs. This repetition process continues till a condition is true. When the condition becomes false, the loop terminates and controls transfers to the statement following the loop.
C++ provides three types of loop control structures: the while loop, the do-while loop and the for loop.
The while loop
Before the discussion of a while loop, let us see a program that finds the sum of a five-digit number.
// Program con23.cpp
#include
#include // header file for abs()–function
void main()
{
int a, b, c, d, e, sum, number, n;
cout << “\nEnter a number – “;
cin >> number;
n = abs(number);
a = n%10;
n = n/10;
b = n%10;
n = n/10;
c = n%10;
n = n/10;
d = n%10;
n = n/10;
e = n%10;
sum = a+b+c+d+e;
cout << “\nSum of digits = ” << sum;
}
In this program, the statements
n % 10 and
n / 10
are repeated over and over. The first statement finds the least significant digits of ‘n’ and assigns it to any other integer variables. The second statement discards the least significant digit and reduces the length of ‘n’ by 1. These statements are repeated about five times till all digits in ‘n’ get exhausted. Thus for a five digit number, we repeat these two statements until n becomes 0 and add the digit at each step.
If you have a 4 digit number then these two steps are repeated for four times, three digit number three times and so on. Whatever may the number of digits of a number, the condition is that repeat these two statements until ‘n’ become 0. Thus it depends upon the number of digits of a number. It may be of any reasonable length using the while loop, we reformulate it so that it can becomes – generalized solution for any number.
The syntax of a while loop is:
while (test-condition)
{
statement(s);
}
The while loop may have a single statement or a set of statements in its body. If the test-condition is true then the statement(s) in the body gets executed. After executing the loop body, the program returns to the test-condition and reevaluates it. This process continues and till the test-condition is true. Like for loop, if the test-condition is false in first attempt, the loop body would never get executed. The while loop is preferred in the circumstances where you do not know how many times you want to repeat the loop body before you start the loop.
Figure 4illustrates the operation of the while loop.
From this figure it is clear that you must do something within the loop body in order to terminate the loop eventually.
Now let us rewrite the program con23.cpp to make it a generalize solution for any number of any digits.
// Program con24.cpp
#include
#include
void main ()
{
int a, sum=0, n , num ;
cout << “\nEnter any number:”;
n = abs(num);
cin >>num;
while (num != 0)
{
a= num % 10;
num = num /10;
sum = sum + a;
}
cout << “ \n Sum of digit =” <}
Here is the output of this program
Enter any number: 1234
Sum of digit =10
Now let us see another program that shows the working of a while loop.
// Program con25.cpp
#include
void main()
{
int num;
cout<< “\nEnter a positive number: “;
cin>>num;
while (num>=0)
{
cout<< “Square of “<cout<< “\nEnter the another positive”;
cin>>num;
}
cout<< “\n you have entered a negative number”;
}
Here are the sample outputs of this program
First Run
Enter a positive number: 6
Square of 6 is 36
Second Run
Enter another position: -7
You have entered a negative number
In this program we ask the user to enter a positive number. When the user enters a negative number the loop ends, since the condition (num>=0) fails. Here there is no idea for the program to know in advance how many times the statements in the loop are to be executed. As long as the test condition is true, the loop continues to be executed. The while loop does not contain any initialization expression and updation expression. It contains only a test-expression. That’s why the loop body must also contain some statement that changes the value of the loop variable; otherwise the loop variable cause the loop to continue indefinitely, such a loop is also known as infinite loop, as illustrated in program con26.cpp.
// Program con26.cpp
#include
void main()
{
int num;
num=1;
while (num>=0)
{
cout<< “\n Square of ”<cout<< “\n Enter the another positive”;
}
cout<< “\n you have entered a negative number”;
}
Here we have not updated the value of num. Therefore the loop will never get terminated.
Another important point to note that do not place a semicolon after the closing parentheses of the test-condition as:
while (num>=0);
Since a semicolon is treated as null statement and the loop body does not contain any such statement that could change the value of the loop. Therefore the loop body would be executed continuously. It works like this
while (num>=0)
{
}
If the while loop’s body contains the single statement then it is optional to enclose the loop body in braces. Therefore the following loop statement is absolutely right:
while (x==0)
cin>>x;
You can also use a while loop even when you know about the number of repetition of the loop. In this case, the loop counter variable is initialized before the while loop and its value is updated within the loop body. Following program calculated the average of three numbers for five different sets.
// Program con27.cpp
#include
void main()
{
int count;
float a, b, c, average;
count=1;
while (count<=5)
{
cout<< “\n Enter three numbers :”;
cin >> a>>b>>c;
average = (a + b + c)/3.0;
cout<< “Average = ”<< average;
count++;
}
}
Here is the sample output of this program:
Enter three numbers :11 12 13
Average = 12
Enter three numbers :12 13.5 24.7
Average = 16.733334
Enter three numbers :10 15.5 17.5
Average = 14.333333
Enter three numbers :45 23.7 56.7
Average = 41.799999
Enter three numbers :5 4 2.4
Average = 3.8
In this program, the loop body is executed five times. Initially the loop counter variable “count” is set to 1 and every time the average is evaluated, the value of count is incremented by when the value of count become 6, the test-condition false and the loop terminates.
Note that the loop counter may be a float variable. It means you can also initialize a loop counter variable, as
num = 0.2;
and update its value as
num = num +0.5;
The do-while loop
The do-while loop is preferred when you want to execute loop body at least once. The syntax of do-while loop is as:
do
{
statement(s);
} while(test-condition);
Unlike while loop where the test-condition is tested before executing any of the statements within the loop body, do-while loop tests the test-condition after executing the statements within the loop. Thus the do-while executes the loop body’s statements at least once, even if the test-condition is false for the first time.
Following program defines the subtle difference between while loop and do-while loop.
(i)
// Program con28.cpp
#include
void main()
{
int x=0;
while (x==1)
{
cout<< “ \n You have done a big mistake “;
cout<< “\n Never try this again “;
}
cout<< “\n I was a big stupid “;
}
(ii)
// Program con29.cpp
#include
void main()
{
int x=0;
do
{
cout<< “\n Thanks god”;
cout<< “\n I have not done a big mistakes”;
} while (x==1);
cout<< “\n I am a big stupid”;
}
In earlier program con28.cpp the test-condition fails for the first time, thus its loop body would never get executed. On the other hand in later program con29.cpp, the loop body would be executed once and then the loop is terminated. Due to their speciality, the do-while loops are rarely used.
The for loop
The for is the simplest and the most popular loop to use and understand. The for loop is used to execute a part of program a fixed number of times. That’s why before entering into the loop, you must know, how many times you want to execute the loop body.
The general form of the for loop is as:
for (initialize_counter; test-condition; update_counter)
{
statement(s);
}
One of the main reasons behind its popularity is that all its loop control elements are gathered in one place. The for loop specifies three things in a single line as:
(a) Initializing a loop counter value
(b) Testing the loop counter to determine if the loop should continue
(c) Update the loop counter each time the program segment within the loop has been executed
All these three activities are enclosed in parenthesis and separated by semicolon from each other. The for loop evaluation initialization just once. Then the test condition determines whether the loop body gets executed. If the test condition is true, then the loop body executes, otherwise if it is false the loop terminates. Here the test-condition is evaluated before each loop cycle. It never executes the loop body when the test condition is false, If the test-condition fails the very first time; the loop body would never get executed. If the test-condition is true, the loop counter is updated after the loop body has been executed. You can either increment or decrement the value of loop counter in order to keep track of the number of loop cycles.
Following program con30.cpp demonstrates this for loop
// Program con30.cpp
#include
void main()
{
int n;
for (n=1; n<=5; n++)
cout<< “\n N=”<}
Here is the output:
N=1
N=2
N=3
N=4
N=5
Now let us see – how does this work?
Initially, the value of the loop counter ‘n’ is set to 1. When the loop is executed first time, the test-condition n<=5 is evaluated. Since initially n is 1, the condition is true, therefore the body of the loop is executed for the first time. After executing the loop body, the control is transferred to the update section of the loop counter. The update section is always executed at the end of the loop. Here the value of n is incremented by 1 each time through the loop. Again the test-condition is checked. If it is true the loop body gets executed, otherwise the loop ends. Thus process continues till the value of the n does not exceeds
When the value of n becomes 6, the test condition becomes false and the control is transferred to the first statement, if any, followed the body of the loop.
Here you have just one statement in the loop body. But you may have more than one statement in the loop body. If you have multiple statements in the loop body then it is necessary to enclose them with in a pair of curly brackets ({ }). If you have just one statement in the loop body then it is optional to enclose it in braces. Each individual statement in the loop body is terminated by semicolon after the final braces of the loop body.
In the earlier program, you have incremented the value of the loop counter in the update section, you can also decrement the loop counter as shown in this program
// Program con31.cpp
#include
void main()
{
int n;
for (n=10; n>=1; n--)
cout<< “\nN=”<}
The output of this program is
N=10 N*N=100
N=9 N*N=81
N=8 N*N=64
N=7 N*N=49
N=6 N*N=36
N=5 N*N=25
N=4 N*N=16
N=3 N*N=9
N=2 N*N=4
N=1 N*N=1
Since we know that C++ is a free- form programming language, just for the good programming style the loop body is indented to the right so that one can easily determine at first look which statements of the program are inside the loop. If you have one statement in the loop then just one statement is indented. If you have a set of statements inside the loop then thew entire set is indented.
Following program should shows this view
// Program con32.cpp
#include
void main()
{
int n;
for (n=1; n<=5; n++)
{
cout<< “\n N=”<cout << “\tN*N=”< cout<< “\tN*N*N=”< }
}
The output of this program is
N=1 N*N=1 N*N*N=1
N=2 N*N=4 N*N*N=8
N=3 N*N=9 N*N*N=27
N=4 N*N=16 N*N*N=64
N=5 N*N=25 N*N*N=125
Unlike C, C++ allows to define a variable near the location it is first used. Thus the following for statement is complete valid statement
for (int n=1;n<=5; n++)
{
//
}
Note that you cannot declare the variables after its usage.
You can also have multiple initialization in the initialization part of the for loop and the multiple increment/decrement expressions in the update section of the for loop. But remember that you can have only test-condition. This test-condition may contain itself several conditions logically combined using logical operators. For example
for (i=1, j=5; i<=5; i++, j--)
cout<< i << “ ” << j << “\n”;
In this program we have initialized a normal loop variable i, and one more variable j. Similarly in update section, we have two expressions: i++ and j--. Note that multiple initialization expressions and multiple expressions are separated by comma.
Let us some different forms of a for loop
(i)
for(n=1;n<=5;)
{
statement(s);
n++; }
(ii)
n=1;
for( ; n<=5;n++)
{
statement(s);
}
(iii)
n=1;
for(;n<=5;)
{
statement(s);
n++;
}
In first case, you have update the value of a loop counter in body of the for loop, but still the semicolon after the test condition is mandatory. In second case you have initially the loop counter before the for loop, but still the semicolon before the test-condition is necessary as far as the third case is concerned, neither the initialization, nor the updation is done in the for statement but still the two semicolons (or before test-condition and or after the test-condition) are necessary.
In programs, which we have seen so far, increase the value of the loop counter by 1 in each iteration. We can also changes that value by changing the update expression. See the behavior of the following program in which we have increase the loop counter by 3.
// Program con33.cpp
#include
void main( )
{
int n;
for( n=1; n<=20; n=n+3)
cout<< “\nN =”<}
The output of this program is
N=1
N=4
N=7
N=10
N=13
N=16
N=19
Once n reaches the value 22, the loop terminates. From this it is clear that update expression can be any valid expression.
Now we will see another typical program of a loop. Let we want to sum the following series:
Sum = x – x3/3! + x5/5! – x7/7! + ……… (-1)n-1 x2n-1/(2n-1)!
// Program con34.cpp
# include
void main ()
{
int i , n ;
float x, sum , num , den , sn = -1;
cout << “\nEnter x and n: ”;
cin >> x >> n;
sum = x;
num = x;
den = 1;
for (i=1 ;i <=n-1 ; i ++)
{
num = num * x * x;
den = den * (2*i) * (2*i+1);
sum = sum + (num /den ) *sn;
sn =-sn;
}
cout << “\nX=” <}
The output of this program is as
Enter x and n: 6 5
X = 6
N = 5
Sum = 7.028572
Whenever someone says you to write a program for a series, firstly calculate the relation, which gives the technique of finding a term in the series from the previous terms. From this series
ith item = (-1)i-1x2i-1 /(2i-1)!(i +1)
item = (-1)I x(2i+1)/(2i+1)!
Thus (i +1)th item = (-1) x2/(2i+1)(2i)* ith item
Nested loops
Like nested if ,while and for , C++ provides the facility of nested while loops, that is defining a while loop with in another while loop. You can also define a while loop in a for loop or vice versa. Following example illustrates the concept of nested loops.
// Program con35.cpp
#include
void main ( )
{
int i, j, temp;
for (i=1;i<=3;i++ )
{
for ( j=1 ;j<=3 ; j++)
{
temp = i * j;
cout << “\nI=”<< i << “\tJ=”<}
}
}
The output of this program is as
I=1 J=1 I*J=1
I=1 J=2 I*J=2
I=1 J=3 I*J=3
I=2 J=1 I*J=2
I=2 J=2 I*J=4
I=2 J=3 I*J=6
I=3 J=1 I*J=3
I=3 J=2 I*J=6
I=3 J=3 I*J=9
The break statement
The break statement is used in a switch statement and in any of the three loops. The break statement transfers the control to the first statement following: the switch or the loop. A break is usually associated with an if statement. When it is encountered in a loop, the control is immediately transferred to the first statement after the loop, without waiting to get back to conditional test.
The break statement is used as:
break;
The operation of the break statement is shown as shown below:
statement;
while (test-condition1)
{
statement(s);
if(test-condition 2)
break;
statement(s);
}
statement;
Program shows how the break statement works?
// Program con36.cpp
#include
void main( )
{
int num , i , flag;
cout<< “\nEnter a number :”;
cin>>num;
i=2;
flag=0;
while (i<=num/2)
{
if(num%i==0)
{
flag = 1;
break;
}
i++;
}
if (flag==0)
cout<< “Prime number: ”<< num;
else
cout<< “Not a prime number: ” << num;
}
Here are the sample outputs of this program
First Run
Enter a number: 14
Not a prime number
Second Run
Enter a number: 17
Prime number
In this the program the moment the condition (num%i==0) results in true, the flag variable is set to1 and the control is transferred out of the while loop. The while loop can also be terminated when the value of i becomes less than or equal to num. After the while, the value of flag is tested. If the flag is 0, then it display a message “Prime number”; otherwise it display the message “Not a prime number”.
Note that if the break statement is encountered in nested loop , the control is transferred outside the loop in which it is placed.
Following program illustrates this point.
// Program con37.cpp
# include
void main()
{
int i ,j , k;
for (i=1;i<=3;i++)
{
for(j=1;j<=3; j++)
{
for( k=1; k<=3;k++)
{
if ((i ==j)||(j==k)||(k==i))
break;
else
cout< }
}
}
}
Here whenever i equals to j, and j equals to k and k equals to i, then the innermost for loop is terminated by the break statement and the control is transferred outside by the inner most for loop.
Here is the output of this program
2 3 1
3 2 1
The continue statement
Unlike the break statement, the continue statement takes the control to the beginning of the loop and skip the rest of the loop body. The continue statement is used in loop only, not in a switch statement, like a switch statement. The continue statement is used as
continue;
Like the break statement, the continue statement is usually associated with an if statement, the operation of the continue statement is shown in figure:
statement;
while (test-condition1)
{
statement (s);
if( test-condition 2)
continue ;
statement (s);
}
statement (s);
Following program clears the concept of continue statement:
// Program con38.cpp
#include
void main()
{
int i , j , k ;
for ( i=1; i<=3; i++)
{
for ( j=1 ;j<=3;j++)
{
for (k=1 ;k<=3;k++)
{
if ((i==j)||(j==k)||(k==i))
continue ;
else
cout << "\n" << i << "\t" << j << "\t" << k ;
}
}
}
}
The output of the program is
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
In this program when the value i equals to j, and j equals to k and k equals to i, the continue statement transfers the control to the inner most for loop by skipping the remaining statement of the inner most for loop.
C++ provides two types of decision making statements: if-else statement and switch-case statement. The conditional operator ? and : can often be used in place of a simple if – else statement. Relational operators compare two numbers and its result is either true or false. A true is indicated by a non-zero value and false by 0.
The logical AND and OR operators combine two or more boolean expressions into one. The logical NOT operator changes the boolean value from true or false, or from false to true. The break statement terminates the switch statement and than the control to the statement, if any following the switch statement. The goto statement transfers the control to the label.
A loop executes the same statement or a set of statements over and over as long as the loop test-condition is true and the loop terminates when the test-condition becomes false. C++ provides three types of the loop – the while loop, the do-while loop and the for loop. The while loop and for loop are entry-controlled loops, that is they examine the test-condition prior to the execution of the loop body. The do-while loop is an exit-condition loop, that is it examines the test-condition after executing the loop body. A loop body may consist of a single statement, or a block of multiple statements enclosed within pair of braces.
The break statement terminates the loop in which it is placed and transfers the control to the first statement following that loop. The continue statement skips the remaining statements of the loop and transfers the control to the top of the loop in which it is placed.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~END~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
More Articles …
Page 7 of 21