There must be a way to make a decision within a program about whether to
execute certain statements or not, or perhaps to decide whether to do one
section of code or to do another section instead.
We examine how to use the C++ if
and switch constructs to make
choices about what to do during the execution of a program.
Here the choice is whether to do a section of code or to skip it entirely. For example, consider the following:
if (Num > 0)
Num = Num * 10;
cout << Num << endl;
If the value in Num is positive, we assign into it 10 times its
value. Then we go on to whatever follows next after the if
statement. In this case, we print out the value of Num.
Note that the code that is selected is the single statement following the
if (CONDITION) construct. Should you want to have multiple
statements governed by the if, you package up those statements
as a block by placing curly braces around them. We will look at an example
of that shortly.
If the value of Num is not positive, then the assignment statement
is skipped. Control passes on to the output statement that follows. Thus if
Num has value -2, the above example prints -2, but if
Num has value 3, it prints 30, because the number gets multiplied
by 10.
Now consider the following similar example. This time the if
selects whether or not to do an entire block of code, which is enclosed in
curly braces.
if (Num > 0)
{
Num = Num * 10;
cout << "Multiplying by 10" << endl;
}
cout << Num << endl;
Can you tell what this section of code does? If Num has
value -2, this example again prints the -2 on the screen. However, if
Num has value 3, the following would be printed:
Multiplying by 10 30
Note that the code that is controlled by the if is indented
by 3 spaces. The curly braces should line up vertically. That way one
can easily see where this important section of code begins and ends.
See the example choice1.cpp. It shows a small but complete program that contains an all or nothing choice.
True/false conditions are needed to control if statements.
These can be constructed in
a number of ways. One way is by comparing two expressions with a
relational operator such as <, >, == (equals), != (not equal),
<=, or >=. For example, consider the following:
x < y
Top - Bottom >= 12
Value == Max
The first example condition checks to see if x is less than
y. The second one checks to see if Top minus
Bottom is greater or equal to 12. Finally, the last one
checks to see if Value and Max are equal. Note
well that you need two equals signs for an equals comparison. A single
equals sign gives an assignment statement,
which is quite a different thing!
This type of choice is usually made with an if..else...
construct. If the condition is true, the first section of code is
executed. If not, the second section of code (the one following the
else) is executed. In either case, after the appropriate
section of code has been executed, control passes to whatever follows
the entire if..else... construct. If a section of code
for one of the choices consists of more than one statement, then those
statements must be packaged up as a block by using curly braces.
The following example shows such a two-way choice. Depending on the
value of the variable, either positive or
not positive is printed. Then, either way, the long
message is printed.
if (Num > 0)
cout << "positive" << endl;
else
cout << "not positive" << endl;
cout << "In all cases we reach here and print this message.";
See the example choice2.cpp. It shows a complete program that contains this type of choice.
Two or more conditions can be combined using the boolean operators && (AND), || (OR), ! (NOT). NOT reverses the truth value of the condition to which it is applied. The result of ANDing or ORing two conditions is most easily summarized in truth tables as shown below. A AND B is only true when both A and B are true. A OR B is only false when both are false.
A B A AND B A B A OR B
--------------------- --------------------
true true true true true true
true false false true false true
false true false false true true
false false false false false false
For example, suppose we want to test if a number grade is within the valid range of 0 to 100. This might be done with a compound condition as follows:
if ((Num >= 0) && (Num <= 100))
{
// Num is valid, so we do whatever processing we want to on Num here.
// Code for this is not shown.
}
else
cout << "Invalid number grade" << endl;
The above program fragment is equivalent to the following. Note the use of
! for NOT and the || for OR. It uses these to write a condition that checks
to see that the value of the variable is not invalid. Note that because of
the parentheses the NOT applies to the OR of the two conditions, that is,
the NOT applies to ((Num < 0) || (Num > 100)).
if (! ((Num < 0) || (Num > 100)))
{
// Num is valid, so we do whatever processing we want to on Num here.
// Code for this is not shown.
}
else
cout << "Invalid number grade" << endl;
The program area4.cpp is a good example of this type of thing. It checks that the length and width of the rectangle are positive numbers before trying to multiply them in order to get the area. This obviously requires two conditions: one for the length and one for the width.
Boolean variables are of type bool. Such a variable can take
on at any point just one of two possible values: true or
false. Here is an outline of a simple example:
bool Error;
Error = false;
if (such and such goes wrong)
Error = true;
else
Do some processing of data;
Do some other stuff in all cases;
if (Error)
cout << "An error has been reported" << endl;
else
cout << "All is OK" << endl;
In this example, the Error variable is used to remember
whether or not an error happened. Later, when some output about the
status of the program is desired, this variable can be testing in an
if statement to decide what to print. Boolean variables
are great for storing true/false, yes/no types of information. If you
want to check if a boolean variable, such as Error is
not true, use something like this:
if (! Error)
cout << "No error has been found" << endl;
else
cout << "An error has been reported" << endl;
Sometimes you need to decide among multiple possibilities. See the program choice3.cpp for an example where we decide which of three sections of code should be executed. This requires at least two conditions. The "extended if" itself looks like this:
if (Num > 0)
cout << " is positive" << endl << endl;
else if (Num == 0)
cout << " is zero" << endl << endl;
else
cout << " is negative" << endl << endl;
Note the "else if" combination. If the first condition is true, the first section of code is executed and the rest is skipped. If not, the second condition is tried. If it is true, the second section of code is executed and the rest is skipped. If the second condition is found to be false, the third section of code is executed. No matter which of the 3 sections of code is executed, control then passes to whatever follows the "extended if" construct. Note the indenting pattern. The indenting of the 3 sections of code makes it easy to see at a glance what the 3 choices are.
The "extended if" can be continued further to handle as many choices as you like. For example, suppose you ask the user to press a letter to indicate a selection from a program menu. You can then use an "extended if" to select the correct section of code to execute. This might look like the following:
char Choice;
cout << "Enter the letter for your choice: ";
cin >> Choice;
if (Choice == 'A')
DoA();
else if (Choice == 'B')
DoB();
else if (Choice == 'C')
DoC();
else if (Choice == 'D')
DoD();
The above code assumes that we have written function called
DoA, DoB, etc. to carry out the desired actions.
We could add an else clause to catch anything other than A, B,
C, or D and write out an error message in such a case, if we wanted.
You might also wonder why we didn't write the above code using separate
if statements. This could, in fact, be done and would look
like the following:
char Choice;
cout << "Enter the letter for your choice: ";
cin >> Choice;
if (Choice == 'A')
DoA();
if (Choice == 'B')
DoB();
if (Choice == 'C')
DoC();
if (Choice == 'D')
DoD();
The blank lines between the separate if statements are not
necessary, but they help to make it clear that these are indeed separate.
Which of these two ways of handling the choice of A, B, C, or D is better?
Both methods clearly work. One way to tell is to draw a decision tree
for each method, showing in each case the choices that are possible:
In each tree, the conditions are labelled with a question mark. If the answer to a question is yes, then the branch to the left is taken. If the answer to a question is no, then the branch to the right is taken. In the decision tree for the "extended if" it is clear that in some cases only one condition is checked, in other cases two conditions are checked before the correct code is selected, in others three conditions are checked, and sometimes all four conditions are checked. On average, though, fewer than all 4 conditions are tested. In the other method, all 4 conditions are always checked. This is needless and a waste of time. Once we know that the variable has A in it, there is no need to check to see if it is a B, etc. Thus our decision trees have helped us to conclude that the "extended if" pattern is more efficient that "separate ifs". In general, you should not use "separate ifs" when an "extended if" can be used instead.
The program grade1.cpp is an example that uses an "extended if" pattern in order to convert a numeric grade to the correct letter grade. It also uses one compound condition.
This construct provides an alternate way to handle multi-way choices when
the conditions are based on equality. For example, in the following code
we want to choose to call one of 4 functions based on whether variable
Choice equals A, B, C, or D (or their lower case equivalents).
char Choice;
cout << "Enter the letter for your choice: ";
cin >> Choice;
switch(Choice)
{
case 'A':
case 'a':
DoOptionA();
break;
case 'B':
case 'b':
DoOptionB();
break;
case 'C':
case 'c':
DoOptionC();
break;
case 'D':
case 'd':
DoOptionD();
}
Note that everything in the switch is enclosed in curly braces, but that braces
are not needed around the code blocks among which we are choosing. When the
switch is executed in checks the value of the variable listed in the
switch() with each case in order. If a match is found, it then
executes the code below that case. Typically the section of code ends with
a break statement which takes us to whatever follows the entire
switch construct. If there is no break at the end of the section
of code, control passes right into the next section of code, whether or not
the variable matches the case at the head of this section of code! That is
why the break statements above are so important. There is no
need of a break after the code for the last case as we will exit from the
switch construct after executing this code anyway. If the value of the
variable doesn't match any of the cases in the switch construct, then the
entire construct is skipped over.
Let's look at a variation on the above example, in which we use an integer variable instead of a character variable. Although we could read in 1, 2, 3, or 4 into a character variable, it would be more typical to read them into an integer variable. Besides, a character variable could not hold a multiple character item like 12, so an integer variable is more flexible here. Note that literal character values are written with single quotes around them as in '2', whereas literal integer or float values are written without quotes as in 2.
int Num;
cout << "Enter the number for your choice: ";
cin >> Choice;
switch(Num)
{
case 1:
DoOption1();
break;
case 2:
DoOption2();
break;
case 3:
DoOption3();
break;
case 4:
DoOption4();
break;
default:
cout << "Invalid number was entered" << endl;
}
This example also illustrates the default case. If the value
of Num doesn't match any of the other cases, then the code for
the default case is executed.