Learning To Program With C++

Making Choices


Introduction

So far our programs have proceeded in a totally predictable fashion, moving from one statement to the next, from the beginning of the program to the end. This sequential approach is limiting. We can only perform simple tasks this way. Don't despair; most computer languages have ways of changing this fixed sequential flow through the program. They do this by testing an expression to see whether it is 'true' or 'false.' If the expression is true, one set of statements, or instructions, is followed. If the expression is false, then a different set of statements or instructions is followed. First, we will explore the nature of truth, at least as far as C++ is concerned. Then we shall look at the if statement which simplest of the selection, or decision-making, statements. Then we'll look at the if-else, the if-else-if..., the conditional and the switch statements. These selection statements are used to alter the sequential flow of the program.


True or false?

When we discussed data types, we mentioned the bool type, which can only be true or false. Selection statements depend upon the evaluation of a boolean expression to true or false. How is this evaluation performed?

C++ has an operator for equality. The equality operator is '==', two equals signs with no space between.

(I can guarantee this will cause some problems in your programs. Even experienced programmers sometimes use the assignment operator '=' mistakenly when they mean to use the equality operator, '=='. )

In math, 3 = 3 is a true statement. It may not be a very useful statement, but it is true! Similarly, we know that 3=4 is false. It's the same in C++. 3 == 3 is true and 3 == 4 is false. We know that 4 is greater than 3; so does C++. The expression 4 > 3 is true, but 4 < 3 is false.

C++ uses relational operators to determine truth values:

Relational Operators
Operator
Meaning
==
is equal to
!=
is not equal to
>
is greater than
>=
is greater than or equal to
<
is less than
<=
is less than or equal to

In evaluating a boolean expression, C++ also determines that the number 0 is false and that non-zero is true. In the other direction, going from a truth value to a number, false is evaluated as 0 and truth is evaluated as 1. So, any non-zero number is true, but true is 1! The inventor of C++ had to pick a consistent number for true, and 1 is the number chosen.

1 #include <iostream>
2 using namespace std;
3
4 int main(){
5
6 cout << "true evaluates to " << true << endl;
7 cout << "false evaluates to " << false << endl;
8
9 cout << "(3==3) evaluates to " << (3==3) << endl;
10 cout << "(4==3) evaluates to " << (4==3) << endl;
11
12 return 0;
13 }
Program 2-01.cpp

Terminal Window
% ./a.out
true evaluates to 1
false evaluates to 0
(3==3) evaluates to 1
(4==3) evaluates to 0
%

C++ also uses logical operators to determine truth values:

Logical Operators
Operator
Meaning
&&
AND
||
OR
!
NOT

These logical operators deserve some explanation. If you are told that you can go out with your friends if you have done your homework AND your chores, you know it isn't enough to just do one. You have to do both. The logical AND works the same way. Like the relational operators above, the AND and OR operators need two arguments (or operands) that are true.

For example, (3 > 2) && (6==2*3) is a true expression since 3 > 2 is true AND 6 == 2*3 is true.

Suppose that you have been told that you can go out with your friends if you do your homework OR if you do your chores. Now, you know that you only have to do one of homework or chores. Doing either will allow you to go out and have fun. The logical OR works the same way. If one of the two arguments to the OR operator is true, then the expression evaluates as true.

For example, (3<2) || (42) is a true expression. (3<2) is false but (42) is non-zero so evaluates as true.

And, even though you only needed to do one of your homework or chores, clearly you will still be allowed to go out if you do both. The same is true in evaluating C++ expression. (3>2) || (42) is still true, even though both its arguments are true.

The NOT operator is pretty simple. It reverses the truth value of its operand.

For example, (3<2) is false, so !(3<2) is true. (42) is true so !(42) isn't.

We can construct a truth table to illustrate the truth values we get from the logical operators:

Truth Table
a
b
a&&b
a||b
!a
true
true
true
true
false
true
false
false
true
false
false
true
false
true
true
false
false
false
false
true

How do we read this table? Look at the first row of true and false values. a is true and b is true so a&&b is true. a||b is true and !a is false. Look now at the third row. a is false and b is true; therefore, a&&b is false, since a and b are not both true. However, a||b is true since one of a or b is true. Finally, a is false so !a is true. Confused? It all becomes clear with a little practice. Let's look at some examples of the type of expressions we might write in our programs.

Some expression evaluations
int a = 13;
int b = 27;
int c = 1;
int total = 4;
Relational
a<b true 13 is less than 27
(2*a+1) <= b true 27 is less than or equal to 27
2*a == b false 26 is not equal to 27
-99 true -99 is not zero
a == b false 13 is not equal to 27
a = b true a is assigned the value 27 which is true
a = --i false --i is 0, so a is assigned the value 0 and the expression is false
a = i-- true (assuming that i is still equal to 1; we're ignoring the previous example that changed the value of i) the value 1 in i is assigned to a before i is decremented to 0. Thus a is 1 and true.
total = 2*a - b + 1 false by precedence, 2*a-b+1 is evaluated first, to 0, and then assigned to total, so total is 0 and the expression is false
(total = 2*a)- b + 1 false first, 2*a=26 is assigned to total, then b is subtracted and 1 is added, again giving 0. This time total has the value 26 and the expression is false since 0.
Logical
!a false a is true, so !a is false
(a==13)&&(!(b-27)) true a==13 is true. (b-27)=0 is false, so !(b-27) is true so the expression is true
(a<b)||(b>a)||(a==b) true this is true for any values of a and b. a must be less than, equal to or greater than b!
(a < b) && (b = 3) true 13 is less than 27. 3 is assigned to b which is non zero so (b = 3) is also true. Thus, the expression is true.
(b = 3) && (a < b) false b = 3 is evaluated first so by the time (a < b) is evaluated, b is 3 and a is still 13 so a is not less than b.

Note, that in the above examples, (a == b) is false but (a = b). A mistake with these can be tricky to find; usually it is the case that (a = b) is used instead of (a == b) and the conditional expression evaluates to true in a program when it shouldn't. I've spent many late night hours hunting down such mistakes.

Now that we are experts on expression evaluation, let's check out the if statement!


The if statement

When the program reaches an if statement, it has to evaluate an expression. If the expression is true, an extra statement or statements are executed.

The form of the if statement is straightforward:

if(expression){
//begin if statement block
firstIfStatement;
secondIfStatement;
.....
.....
.....
lastIfStatement;
} //end if statement
nextStatement;

The if word is required. So are the parentheses around the test expression. The curly braces { ... } enclose the statement block for the statements to be executed if the expression is true. After executing the statements in the statement block, normal program flow resumes at the first statement after the if statement. If the expressoin is false, none of the statements in the block are executed; execution goes straight to the statement after the if statement.

The following program shows how the evaluation of the boolean test expression determines whether the if statement block is executed.

Program 2-02.cpp
1 #include <iostream>
2 using namespace std;
3
4 int main(){
5
6 if(true){
7 cout << "Test expression is true so this statement executes" << endl;
8 }
9
10 if(false){
11 cout << "Test expression is false so this doesn't execute" << endl;
12 }
13
14 if(42){
15 cout << "Non-zero so this does execute" << endl;
16 }
17
18 if(0){
19 cout << "0 so this doesn't execute" << endl;
20 }
21
22 if(3==3){
23 cout << "Test expression true" << endl;
24 }
25
26 if(4==3){
27 cout << "Test expression false. You won't see this!" << endl;
28 }
29
30 if(!0){
31 cout << "0 is false so !0 is true" << endl;
32 }
33
34 if(!42){
35 cout << "42 is true so !42 is false" << endl;
36 }
37
38 return 0;
39 }

Terminal Window
% ./a.out
Test expression is true so this statement executes
Non-zero so this does execute
Test expression true
0 is false so !0 is true
%

The following program shows how you might use the if statement. The program asks the user to input two numbers, then finds the maximum of the two numbers.

Program 2-03.cpp
1 #include <iostream>
2 using namespace std;
3
4 int main(){
5
6 int number1 = 0, number2 = 0;
7
8 cout << "Enter an integer:\t";
9 cin >> number1;
10
11 cout << "Enter another integer:\t";
12 cin >> number2;
13
14 if(number1 > number2){
15 cout << "The larger number is " << number1 << endl;
16 }
17
18 if(number1 < number2){
19 cout << "The larger number is " << number2 << endl;
20 }
21
22 if(number1 == number2){
23 cout << "Both numbers are the same" << endl;
24 }
25
26 return 0;
27 }

Code Explanation
14
If the first number entered is larger than the second, then the test expression is true, the if-statement block is entered and the first (larger) number is printed to the console.
If the first number entered is not larger than the second, then the test expression is false and the if-statement block
18
If the first number entered is smaller than the second, then the test expression is true, the if-statement block is entered and the second (larger) number is printed to the console.
22
If both numbers entered are the same, then the test expression is true and the if-statement block is entered.
Note:
These three if-statements cover all possibilities. number1 must be either larger than, smaller than or the same as number2. Therefore, for any choice of numbers, one of the three if-statement blocks must be entered.

Output for a typical run of this program might be:

Terminal Window
% ./a.out
Enter an integer: 23
Enter another integer: 35
The larger number is 35
%

The following program prompts the user for the radius of a circle. Then the user is asked whether they want to know the radius or the circumference or both. The requested answer is printed to the screen.

Program 2-04.cpp
1 #include <iostream>
2 using namespace std;
3
4 const float PI = 3.14159;
5
6 int main(){
7
8 float radius = 0, circumference = 0, area = 0;
9 char reply = 'b';
10
11 cout << "Enter a value for the radius of a circle:\t";
12 cin >> radius;
13
14 circumference = 2*PI*radius;
15 area = PI*radius*radius;
16
17 cout << "Enter C for the circumference, A for the area,\n"
18 << "or B for both:\t";
19 cin >> reply;
20
21 if(reply=='C' || reply=='c'){
22 cout << "Circumference = " << circumference << endl;
23 }
24
25 if(reply=='A' || reply=='a'){
26 cout << "Area = " << area << endl;
27 }
28
29 if(reply=='B' || reply=='b'){
30 cout << "Circumference = " << circumference
31 << ", Area = " << area << endl;
32 }
33
34 return 0;
35 }

There are a number of points in this program that are worthy of discussion:

Code Explanation
4
const float PI = 3.14159;
It is good programming practice to declare numbers that don't change throughout the program as constants. This is recommended for a couple of reasons:
The variable PI is clearer to someone reading your code than 3.14159.
The values of some numbers in a program may change over time. Whereas it is not very likely that the value of PI will change in the near future, consider a program that calculates interest earned on money in your bank account. The interest rate at the bank will change so it is better to define the interest rate as a const RATE (or some other descriptive name). Then, when the interest rate changes, the programmer doesn't have to search throughout the program each occurrence of something like the number 2.0342 and change that number to 2.0489. Instead, the programmer makes a single change to the variable declaration placed conveniently near the top of the program.
21
Notice that the program allows the user to enter their request in upper or lower case letters. For the circumference, the program accepts both 'C' and 'c' to make life a little easier if the user makes the wrong entry. Upper and lower case responses are accepted for 'area' and 'both'. As we progress in C++, we will introduce more error-checking, so that we can deal with incorrect entries.
Note:
To test for two different character, we use the test expression (reply=='A' || reply=='a'). We are checking "does the reply equal 'A' or does the reply equal 'a'?". Why can't we ask "does the reply equal 'A' or 'a'" as we would if we were asking the question in English?
Suppose, instead, we had used the test expression (reply == ('A' || 'a')), which is more like the question we'd ask in English. The character 'A' has ASCII value 65, which is non-zero. So, ('A' || 'a') is true and has numerical value 1. So, our test expression (reply == ('A' || 'a')) is really the expression (reply == 1), which will be false for if reply is 'A' or 'a'. The logic that we use when talking to each other is very different from the logic used by a computer!

There are a couple of other things to consider when using an if statement:

  1. If there is only one single statement in the statement block, the C++ language rules don't require the curly braces that we have been using. If an if statement does not have curly braces, the compiler simply uses the following statement as the one to be executed if the test expression evaluates to true. If the expression evaluates to false, then the following statement is ignored.
    Why have we been using the curly braces when it hasn't been necessary?
    When programming, it is common to make changes to parts of the program that is already written. An if statement with a single statement may have extra statements added later. And it is easy to forget to add the curly braces when the extra statement is added, causing your program to produce unintended results.
  2. Notice that there is no semi-colon following the test expression. Most C++ statements end with a semi-colon but not any of the if, if-else, if-else-if... statements (or the iteration statements that we'll meet in the next part). If a semi-colon is inserted after the test expression, the compiler views this as the statement attached to the if statement. A semi-colon on its own is a null statement, a statement that does nothing - there is nothing to do before the semi-colon! In the program below, you can see that the semi-colon causes the first cout statement to be sent to the screen even though the test expression is false; the compiler assumes that the statements following the null statement are the continuation of the program and will execute them regardless of the test condition.

Program 2-05.cpp
1 #include <iostream>
2 using namespace std;
3
4 int main(){
5
6 cout << endl << "With curly braces:" << endl;
7 if(false){
8 cout << "This is the first statement" << endl;
9 cout << "This is the second statement" << endl;
10 }
11 cout << "This is the third statement" << endl;
12
13 cout << endl << "Without curly braces:" << endl;
14 if(false)
15 cout << "This is the first statement" << endl;
16 cout << "This is the second statement" << endl;
17 cout << "This is the third statement" << endl;
18
19 cout << endl << "With a semi-colon:" << endl;
20 if(false);
21 cout << "This is the first statement" << endl;
22 cout << "This is the second statement" << endl;
23 cout << "This is the third statement" << endl;
24
25 return 0;
26 }

Terminal Window
% ./a.out
With curly braces:
This is the third statement

Without curly braces:
This is the second statement
This is the third statement

With a semi-colon:
This is the first statement
This is the second statement
This is the third statement
%




The if-else statement

Quite often, we want to execute one statement (or block of statements) if the test expression is true and a different statement (or block) is the test expression is false. We have shown how to do this, in the section above, using two if statements. This can be done more efficiently with a single if-else statement.

The form (or syntax) of the if-else statement is an extension of the form of the if statement.

if(expression){
//begin if statement block
firstIfStatement;
secondIfStatement;
.....
.....
.....
lastIfStatement;
} //end if statement block
else{
firstElseStatement;
secondElseStatement;
.....
.....
.....
lastElseStatement;
} //end else statement block
nextStatement;

Consider the following problem: You want to calculate how much money you earn in a week. Your hourly rate is $10.75 but after working 40 hours in one week, you get paid at "time-and-a-half" (1.5 times your normal hourly rate) for the hours over 40 that you work. For example, if you work 44 hours, you will earn $10.75 times 40 hours and $10.75 times "time-and-a-half" times 4 hours. Write a program that asks how many hours were worked and calculates the money earned.

Program 2-06.cpp

Terminal Window
% ./a.out
How many hours did you work this week? 42.5
You earned $470.312 this week
%

1 #include <iostream>
2 using namespace std;
3
4 const float HOURLY_RATE = 10.75;
5 const float OVERTIME_RATE = HOURLY_RATE*1.5;
6 // declare a variable for how many hours at single time
7 const float SINGLE = 40;
8
9 int main(){
10
11 float hours = 0, earned = 0;
12
13 cout << "How many hours did you work this week?\t";
14 cin >> hours;
15
16 if(hours <= SINGLE){
17 //worked SINGLE or less hours so there is no overtime pay
18 earned = hours*HOURLY_RATE;
19 }
20 else{
21 //then you earned SINGLE hours at HOURLY_RATE
22 earned = SINGLE*HOURLY_RATE;
23 //and you earned (hours - SINGLE) hours at OVERTIME_RATE
24 earned += (hours - SINGLE)*OVERTIME_RATE;
25 }
26
27 cout << "You earned $" << earned << " this week" << endl;
28
29 return 0;
30 }

The output from the program is accurate, but not very pretty. We need to learn something about formatting output so that we can get the answer in dollars and cents.

C++ includes ways to manipulate the look of output. We use setiosflags(ios::fixed | ios::showpoint) to get fixed (not scientific, like 4.7e+2) output and a decimal point. We want two decimal points of precision to get cents, so we use setprecision( ) with the number 2 between the braces. (We won't spend a lot of time formatting output, so what is needed will be presented when it becomes necessary.) To use the above, we need to include the <iomanip> header file.

To correct the output, add the line #include <iomanip> at the top of the program 2-06.cpp or after #include <iostream>. Then, somewhere before the cout statement that sends the amount earned to the screen, add the line cout << setiosflags(ios::fixed | ios::showpoint) << setprecision(2); and run the program again. The output should now look like this:

Terminal Window
% ./a.out
How many hours did you work this week? 42.5
You earned $470.31 this week
%

Exercises:



Nested if Statements


coming soon


The Conditional Operator


coming soon


The switch Statement



coming soon