Wrox Press C++ Tutorial
Unless we want to make decisions on a whim for the rest of our lives, we need a mechanism for comparing things. This involves some new operators called relational operators. Because all information in your computer is ultimately represented by numerical values (we saw in the last chapter how character information is represented by numeric codes), comparing numerical values is the essence of practically all decision making. We have six fundamental operators for comparing two values:
|
less than |
|
less than or equal to |
|
greater than |
|
greater than or equal to |
|
equal to |
|
not equal to |
The 'equal to' comparison operator has two successive '=' signs. This is not the same as the assignment operator, which only consists of a single '=' sign. It's a pretty common mistake to use the assignment operator instead of the comparison operator, so watch out for this potential cause of confusion.
Each of these operators compares two values returns one of the two possible Boolean values: true if the comparison is true, or false if it is not. We can see how this works by having a look at a few simple examples of comparisons. Suppose we have integer variables i and j with the values 10 and -5 respectively. Then the expressions,
i > j i!= j j > 8 i <= j+15
all return the value true.
Let's further assume that we have the following variables defined:
char first = 'A', last = 'Z';
We can now write some examples of comparisons using character variables. Take a look at these:
first == 65; first < last 'E' <= first first != last
All four of these involve comparing ASCII code values. The first expression returns true, since first was initialized with 'A', which is the equivalent of decimal 65. The second expression checks whether the value of first, which is 'A', is less than the value of last, which is 'Z'. The capital letters are represented by an ascending sequence of numerical values from 65 to 90, 65 representing 'A' and 90 representing 'Z', so this comparison will also return the value true. The third expression returns the value false, since 'E' is greater than the value of first. The last expression returns true, since 'A' is definitely not equal to 'Z'.
Let's consider some slightly more complicated numerical comparisons. We can define some variables with the following statements:
int i = -10, j = 20;
double x = 1.5, y = -0.25E-10;
Take a look at these expressions:
-1 < y j lt; (10-i) 2.0*x >= (3+y)
As you can see, we can use expressions resulting in a numerical value as operands in comparisons. Note that none of the parentheses are strictly necessary, because addition, subtraction, multiplication and division have higher precedence that the relational operators. They do, however, help to make the expressions clearer. The first comparison is true and so returns the bool value true. The variable y has a very small negative value, -0.000000000025, and so is greater than -1. The second comparison returns the value false - the expression 10-i has the value 20 which is the same as j. The third expression returns true, since the expression 3+y is slightly less than 3.
We can use relational operators to compare values of any of the basic types, so all we need now is a practical way of using the results of a comparison to modify the behavior of a program. Let's look into that right now.
The basic if statement allows your program to execute a single statement, or a block of statements enclosed within curly braces, if a given condition returns the value true. This is illustrated in this figure:

A simple example of an if statement is:
if(letter == 'A')
cout << "The first capital, alphabetically speaking.";
The condition to be tested appears in parentheses immediately following the keyword, if. Note the position of the semicolon here. It goes after the statement following the if; there shouldn't be a semicolon after the condition in parentheses. You can also see how the statement following the if is indented to indicate that it is only executed when the if condition returns the value true. The indentation is not necessary for the program to execute, but it helps you to recognize the relationship between the if condition and the statement that depends on it.
The output statement will only be executed if the variable letter has the value 'A'. We could extend this example to change the value of letter if it contains the value 'A':
if(letter == 'A')
{
cout << "The first capital, alphabetically speaking.";
letter = 'a';
}
Here we execute the statements in the block only if the condition (letter == 'A') returns the value true. Without the curly braces, only the first statement would be the subject of the if, and the statement assigning the value 'a' to letter would always be executed. Note that there is a semicolon after each of the statements in the block, and not after the closing brace at the end of the block. There can be as many statements as you like within the block. Now, as a result of letter having the value 'A', we change its value to 'a' after outputting the same message as before. If the condition returns false, then neither of these statements will be executed.
The statement that is to be executed when the condition in an if statement is true can also be an if. This arrangement is called a nested if. The condition for the inner if is only tested if the condition for the outer if is true. An if that is nested inside another can also contain a nested if. You can generally continue nesting ifs one inside the other like this for as long as you know what you are doing.
We can demonstrate the nested if with a working example:
// EX2_01.CPP
// A nested if demonstration
#include <iostream>
using namespace std;
int main()
{
char letter = 0; // Store input in here
cout << endl
<< "Enter a letter: "; // Prompt for the input
cin >> letter; // then read a character
if(letter >= 'A') // Test for 'A' or larger
if(letter <= 'Z') // Test for 'Z' or smaller
{
cout << endl
<< "You entered a capital letter."
<< endl;
return 0;
}
if(letter >= 'a') // Test for 'a' or larger
if(letter <= 'z') // Test for 'z' or smaller
{
cout << endl
<< "You entered a small letter."
<< endl;
return 0;
}
cout << endl << "You did not enter a letter." << endl;
return 0;
}
This program starts with the usual comment lines, then the #include statement for the header file supporting input/output, and the using directive because those input/output routines belong to the namespace std. The first action in the body of main() is to prompt for a letter to be entered. This is stored in the char variable letter.
The if statement that follows the input checks whether the character entered is 'A' or larger. Since the ASCII codes for lower case letters (97 to 122) are greater than those for upper case letters (65 to 90), entering a lower case letter causes the program to execute the first if block, as (letter >= 'A') will return true for all letters. In this case, the nested if, which checks for an input of 'Z' or less is executed. If it is 'Z' or less, then we know that we have a capital letter, so the message is displayed and we are done. We execute a return statement to end the program. Both statements are enclosed between braces, so they are both executed when the nested if condition returns true.
The next if checks whether the character entered is lower case, using essentially the same mechanism as the first if, displays a message and returns.
If the character entered is not a letter, then the output statement following the last if block will be executed. This displays a message to the effect that the character entered was not a letter. The return is then executed.
You can see that the relationship between the nested ifs and the output statement is much easier to follow because of the indentation applied to each.
A typical output from this example is:

You could easily arrange to change upper case to lower case by adding just one extra statement to the if, checking for upper case:
if(letter >= 'A') // Test for 'A' or larger
if(letter <= 'Z') // Test for 'Z' or smaller
{
cout << endl
<< "You entered a capital letter.";
<< endl;
letter += 'a' - 'A'; // Convert to lower case
return 0;
}
This involves adding one additional statement. This statement for converting from upper to lower case increments the letter variable by the value 'a' - 'A'. It works because the ASCII codes for 'A' to 'Z' and 'a' to 'z' are two groups of consecutive numerical codes, so the expression 'a' - 'A' represents the value to be added to an upper case letter to get the equivalent lower case letter.
You could equally well use the equivalent ASCII values for the letters here, but by using the letters we've ensured that this code would work on computers where the characters were not ASCII, as long as both the upper and lower case sets are represented by a contiguous sequence of numeric values.
There is a library function provided with Visual C++ to convert letters to upper case, so you don't normally need to program for this yourself. It has the name toupper() and appears in the standard library file cctype. You will see more about standard library facilities when we get to look specifically at how functions are written.
The if statement that we have been using so far executes a statement if the condition specified returns true. Program execution then continues with the next statement in sequence. We also have a version of the if, which allows one statement to be executed if the condition returns true, and a different statement to be executed if the condition returns false. Execution then continues with the next statement in sequence. Remember that a block of statements can always replace a single statement, so this also applies to these ifs.
Here's an extended if example:
// EX2_02.CPP
// Using the extended if
#include <iostream>
using namespace std;
int main()
{
long number = 0; // Store input here
cout << endl
<< "Enter an integer number
less than 2 billion: ";
cin >> number;
if(number%2L) // Test remainder after division by 2
cout << endl // Here if remainder 1
<< "Your number is odd." << endl;
else
cout << endl // Here if remainder 0
<< "Your number is even." << endl;
return 0;
}
Typical output from this program is:

After reading the input value into number, the value is tested by taking the remainder after division by two (using the remainder operator, %, that we saw in the last chapter) and using that as the condition for the if. In this case, the condition of the if statement returns an integer, not a Boolean. The if statement interprets a non-zero value returned by the condition as true, and interprets zero as false. In other words, the statement,
if(number%2L)
is equivalent to:
if(number%2L != 0)
If the remainder is 1, then the condition is true, and statement immediately following the if is executed. If the remainder is 0, then the condition is false, and the statement following the else keyword is executed.
The relational operators return only the values true or false. In an if statement, the condition may also take the form of any of the basic data types that we saw in the last chapter. In such a case, the if statement always interprets a non-zero value returned by the condition as true, and a zero as false.
Since the remainder of a division of an integer by two can only be one or zero, we have commented the code to indicate this fact. After either outcome, the return statement is executed to end the program.
The else keyword is written without a semicolon, similar to the if part of the statement. Again, indentation is used as a visible indicator of the relationship between various statements. You can clearly see which statement is executed for a true or non-zero result, and which for a false or zero result. You should always indent the statements in your programs to show their logical structure.
The if-else combination provides a choice between two options. The general logic of the if-else is shown here:

The arrows in the diagram indicate the sequence in which statements are executed, depending on whether the if condition returns true or false.
As we have seen, you can nest if statements within if statements. You can also nest if-else statements within ifs, ifs within if-else statements, and if-else statements within if-else statements. This provides us with considerable room for confusion, so let's look at a few examples. Taking the first case first, an example of an if-else nested within an if might be:
if(coffee == 'y')
if(donuts == 'y')
cout << "We have coffee and donuts.";
else
cout << "We have coffee, but not donuts";
The test for donuts is executed only if the result of the test for coffee returns true, so the messages reflect the correct situation in each case. However, it is easy to get this confused. If we write much the same thing with incorrect indentation, we can be trapped into the wrong conclusion:
if(coffee == 'y')
if(donuts == 'y')
cout << "We have coffee and donuts.";
else // This else is indented incorrectly
cout << "We have no coffee..."; // Wrong!
This mistake is easy to see here, but with more complicated if structures we need to keep in mind the rule about which if owns which else.
An else always belongs to the nearest preceding if which is not already spoken for by another else.
Whenever things look a bit complicated you can apply this rule to sort things out. When you are writing your own programs you can always use braces to make the situation clearer. It isn't really necessary in such a simple case, but we could write the last example as follows:
if(coffee == 'y')
{
if(donuts == 'y')
cout << "We have coffee and donuts.";
else
cout << "We have coffee, but not donuts";
}
This should make it should be absolutely clear. Now that we know the rules, understanding the case of an if nested within an if-else becomes easy:
if(coffee == 'y')
{
if(donuts == 'y')
cout << "We have coffee and donuts.";
}
else
if(tea == 'y')
cout << "We have tea, but not coffee";
Here the braces are essential. If we leave them out, the else would belong to the if which is looking out for donuts. In this kind of situation, it is easy to forget to include them, and hence create an error that may be hard to find. A program with this kind of error will compile fine, and even produce the right results some of the time.
If we removed the braces in this example, we'd get the right results only as long as coffee and donuts are both equal to 'y' so that the if(tea == 'y') check wouldn't be executed.
Here we'll look at if-else statements nested in if-else statements. This can get very messy, even with just one level of nesting. Let's beat the coffee and donuts analysis to death by using it again:
if(coffee == 'y')
if(donuts == 'y')
cout << "We have coffee and donuts.";
else
cout << "We have coffee, but not donuts";
else
if(tea == 'y')
cout << "We have no coffee, but we have tea,
and maybe donuts...";
else
cout << "No tea or coffee, but maybe donuts...";
The logic here doesn't look quite so obvious, even with the correct indentation. No braces are necessary, as the rule you saw earlier will verify that this is correct, but it would look a bit clearer if we included them:
if(coffee == 'y')
{
if(donuts == 'y')
cout << "We have coffee and donuts.";
else
cout << "We have coffee, but not donuts";
}
else
{
if(tea == 'y')
cout << "We have no coffee, but we have tea,
and maybe donuts...";
else
cout << "No tea or coffee, but maybe donuts...";
}
There are much better ways of dealing with this kind of logic in a program. If you put enough nested ifs together, you can almost guarantee a mistake somewhere. The following section will help to simplify things.
As we have just seen, using ifs where we have two or more related conditions can be a bit cumbersome. We have tried our iffy talents on looking for coffee and donuts, but in practice you may want to check much more complex conditions. You could be searching a personnel file for someone who is over 21 but under 35, female with a college degree, unmarried and speaks Hindi or Urdu. Defining a test for this could involve the mother of all ifs.
Logical operators provide a neat and simple solution. Using logical operators, we can combine a series of comparisons into a single expression, so we end up needing just one if, virtually regardless of the complexity of the set of conditions.
We have just three logical operators:
|
logical AND |
|
logical OR |
|
logical negation (NOT) |
We'll first consider what each of these is used for in general terms, then we'll look at an example.
You would use the AND operator, &&, where you have two conditions that must both be true for a true result. You want to be rich and healthy. For example, you could use the && operator when you are testing a character to determine whether it's an upper case letter. The value being tested must be both greater than or equal to 'A' AND less than or equal to 'Z'. Both conditions must return true for the value to be a capital letter.
As before, these conditions may return numerical values. Remember that a non-zero value is treated as true, while zero is treated as false. Conversely, the bool value true has the value 1 when converted to an integer, while false has the value 0.
Taking the example of a value stored in a char variable letter, we could replace the test using two ifs for one that uses only a single if and the && operator:
if((letter >='A') && (letter<='Z'))
cout << "This is a capital letter.";
The parentheses inside the if expression ensure that there is no doubt that the comparison operations are executed first, which makes the statement clearer. Here, the output statement will be executed only if both of the conditions combined by the operator && are true.
Just as with binary operators in the last chapter, we can represent the effect of a particular logical operator using a truth table. The truth table for && is as follows:
&& |
0 | 1 |
| 0 | 0 | 0 |
| 1 | 0 | 1 |
The row headings of the left and the column headings at the top represent the value of the logical expressions to be combined by the operator &&. Thus, to determine the result of combining a true condition (1) with a false condition (0), select the row with 1 at the left and the column with 0 at the top, and look at the intersection of the row and column for the result (0).
The OR operator, ||, applies when you have two conditions and you want a true result if either one of them is true or both are true. For example, you might be considered creditworthy for a loan from the bank if your income was at least $100,000 a year, or you had $1,000,000 in cash. This could be tested using the following if:
if((income >= 100000.00) || (capital >= 1000000.00))
cout << "How much would you like to borrow,
Sir, (grovel, grovel)?";
The ingratiating response emerges when either or both of the conditions are true. (A better response might be, "Why do you want to borrow?" It's strange how banks will only lend you money if you don't need it.)
We can also construct a truth table for the || operator:
|
0 | 1 |
| 0 | 0 | 1 |
| 1 | 1 | 1 |
As you can see, you only get a false result if both conditions are false.
The third logical operator, !, takes one operand with a logical value, true or false, and inverts its value. So if the value of test is true then !test is false, and if test is false then !test is true. To take the example of a simple expression, if x has the value 10, the expression:
!(x>5)
is false, since x>5 is true.
We could also apply the ! operator in an expression that was a favorite of Charles Dickens:
!(income>expenditure)
If this expression is true, the result is misery, at least as soon as the bank starts bouncing your checks.
Finally, we can apply the ! operator to other basic data types. Suppose we have a variable rate of type float, which has the value 3.2. For some reason we might want to use the expression:
!(rate)
The value 3.2 is non-zero, and converts to the Boolean true: so the result of this expression is false.
You can combine conditional expressions and logical operators to any degree that you feel comfortable with. For example, we could construct a test for whether a variable contained a letter just using a single if. Let's write it as a working example:
// EX2_03.CPP
// Testing for a letter using logical operators
#include <iostream>
using namespace std;
int main()
{
char letter = 0; // Store input in here
cout << endl
<< "Enter a character: ";
cin >> letter;
// Test for alphabetic
if(((letter>='A')&&(letter<='Z')) ||
((letter>='a')&&(letter<='z')))
cout << endl
<< "You entered a letter." << endl;
else
cout << endl
<< "You didn't enter a letter." << endl;
return 0;
}
This example starts out in the same way as Ex3_01.cpp, by reading a character after a prompt for input. The interesting part of the program is in the if condition. This consists of two logical expressions combined with the || (OR) operator, so that, if either is true, the condition returns true and the message:
You entered a letter.
is displayed. If both logical expressions are false, then the else statement is executed which displays the message:
You didn't enter a letter.
Each of the logical expressions combines a pair of comparisons with the operator && (AND), so both comparisons must return true if the logical expression is to be true. The first logical expression returns true if the input is an upper case letter, and the second returns true if the input is a lower case letter.
The conditional operator is sometimes called the ternary operator because it involves three operands. It is best understood by looking at an example. Suppose we have two variables, a and b, and we want to assign the maximum of a and b to a third variable c. We can do this with the statement:
c = a>b ? a : b; // Set c to the maximum of a and b
The first argument of the conditional operator is a logical expression, in this case a>b. If this expression returns true then the second operand-in this case a-is selected as the value resulting from the operation. If the first argument returns false then the third operand-in this case b-is selected as the value. Thus, the result of the conditional expression a>b ? a : b is a if a is greater than b, and b otherwise. This value is stored in c. The use of the conditional operator in this assignment statement is equivalent to the if statement:
if(a>b)
c = a;
else
c = b;
The conditional operator can be written generally as:
condition ? expression1 : expression2
If the condition evaluates as true, then the result is the value of expression1, and if it evaluates to false, then the result is the value of expression2.
A common use of the conditional operator is to control output, depending on the result of an expression or the value of a variable. You can vary a message by selecting one text string or another depending on the condition specified.
// EX2_04.CPP
// The conditional operator selecting output
#include <iostream>
using namespace std;
int main()
{
int nCakes = 1; // Count of number of cakes
cout << endl
<< "We have " << nCakes << " cake"
<< ((nCakes>1) ? "s." : ".")
<< endl;
++nCakes;
cout << endl
<< "We have " << nCakes << " cake"
<< ((nCakes>1) ? "s." : ".")
<< endl;
return 0;
}
The output from this program will be:

First we initialize the nCakes variable with the value 1, then perform an output statement that shows us the number of cakes. The part that uses the conditional operator simply tests the variable to determine whether we have a singular cake or plural cakes:
((nCakes>1) ? "s." : ".")
This expression evaluates to "s." if nCakes is greater than 1, or "." otherwise. This allows us to use the same output statement for any number of cakes. We show this in the example by incrementing the nCakes variable and repeating the output statement.
There are many other situations where you can apply this sort of mechanism; selecting between "is" and "are", for example.
The switch statement enables you to select from multiple choices based on a set of fixed values for a given expression. It operates like a physical rotary switch in that you can select one of a fixed number of choices; some makes of washing machine provide a means of choosing an operation for processing your laundry in this way. There are a given number of possible positions for the switch, such as cotton, wool, synthetic fiber, and so on, and you can select any one of them by turning the knob to point to the option that you want.
In the switch statement, the selection is determined by the value of an expression that you specify. You define the possible switch positions by one or more case values, a particular one being selected if the value of the switch expression is the same as the particular case value. There is one case value for each possible choice in the switch - the case values must be distinct.
If the value of the switch expression does not match any of the case values, then the switch automatically selects the default case. You can, if you wish, specify the code for the default case, as we will do below; otherwise, the default is to do nothing.
We can examine how the switch statement works with the following example:
// EX2_05.CPP
// Using the switch statement
#include <iostream>
using namespace std;
int main()
{
int choice = 0; // Store selection value here
cout << endl
<< "Your electronic recipe book
is at your service." << endl
<< "You can choose from the following delicious
dishes: " << endl
<< endl << "1 Boiled eggs"
<< endl << "2 Fried eggs"
<< endl << "3 Scrambled eggs"
<< endl << "4 Coddled eggs" << endl
<< endl << "Enter your selection number: ";
cin >> choice;
switch(choice)
{
case 1: cout << endl << "Boil some eggs."
<< endl;
break;
case 2: cout << endl << "Fry some eggs."
<< endl;
break;
case 3: cout << endl << "Scramble some eggs."
<< endl;
break;
case 4: cout << endl << "Coddle some eggs."
<< endl;
break;
default: cout << endl <<"You entered a wrong number,
try raw eggs."
<< endl;
}
return 0;
}
After defining your options in the stream output statement, and reading a selection number into the variable choice, the switch statement is executed with the condition specified as simply choice in parentheses, immediately following the keyword switch. The possible options in the switch are enclosed between braces and are each identified by a case label. A case label is the keyword case, followed by the value of choice that corresponds to this option, and terminated by a colon.
As you can see, the statements to be executed for a particular case are written following the colon at the end of the case label, and are terminated by a break statement. The break transfers execution to the statement after the switch. The break isn't mandatory, but if you don't include it, all the statements for the cases following the one selected will be executed, which isn't usually what you want. You can demonstrate this by removing the break statements from this example and seeing what happens.
If the value of choice doesn't correspond with any of the case values specified, the statements preceded by the default label are executed. A default case isn't essential. In its absence, if the value of the test expression doesn't correspond to any of the cases, the switch is exited and the program continues with the next statement after the switch.
Each of the case constant expressions must be constant and unique. The reason that no two case constants can be the same is that the compiler would have no way of knowing which case statement should be executed for that particular value. However, different cases don't need to have a unique action. Several cases can share the same action, as shown here:
// EX2_06.CPP
// Multiple case actions
#include <iostream>
using namespace std;
int main()
{
char letter = 0;
cout << endl
<< "Enter a small letter: ";
cin >> letter;
switch(letter*(letter>='a' && letter <='z'))
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u': cout << endl << "You entered a vowel.";
break;
case 0: cout << endl << "It is not a small letter.";
break;
default: cout << endl << "You entered a consonant.";
}
cout << endl;
return 0;
}
In this example, we have a more complex expression in the switch. If the character entered isn't a lower case letter, then the expression:
(letter>='a' && letter<='z')
will result in the value 0. Then, letter is multiplied by this expression, so the switch expression would be set to 0 if a lower case letter wasn't entered. This will then cause the statements following the case label case 0 to be executed.
If a lower case letter was entered, the expression above will result in the value 1. Multiplying letter by 1 results in the switch expression having the same value as letter. For all values corresponding to vowels, the same output statement is executed since we haven't used break statements to separate these case labels. You can see that a single action can be taken for a number of different cases by writing each of the case labels one after the other before the statements to be executed. If a lower case letter that is a consonant is entered as program input, the default case label statement is executed.
The if statement provides you with the flexibility to choose to execute one set of statements or another, depending on a specified condition, so the statement execution sequence is varied depending on the values of the data in the program. The goto statement, in contrast, is a blunt instrument. It enables you to branch to a specified program statement unconditionally. The statement to be branched to must be identified by a statement label, which is an identifier defined according to the same rules as a variable name. This is followed by a colon and placed before the statement requiring labeling. Here is an example of a labeled statement:
myLabel: cout << "myLabel branch has been activated"
<< endl;
This statement has the label myLabel. An unconditional branch to this statement would be written as follows:
goto myLabel;
Whenever possible, you should avoid using gotos in your program. They tend to encourage very convoluted code that can be extremely difficult to follow.
As the goto is theoretically unnecessary - there's always an alternative approach to using goto - a significant cadre of programmers say you should never use it. I don't subscribe to such an extreme view. It is a legal statement after all, and there are occasions when it can be convenient. However, I do recommend that you only use it where you can see an obvious advantage over other options that are available.