Day 4. Creating Expressions and Statements

At its heart, a program is a set of commands executed in sequence. The power in a program comes from its capability to execute one or another set of commands, based on whether a particular condition is true or false.

Today, you will learn

• What statements are

• What blocks are

• What expressions are

• How to branch your code based on conditions

• What truth is, and how to act on it

Starting with Statements

In C++, a statement controls the sequence of execution, evaluates an expression, or does nothing (the null statement). All C++ statements end with a semicolon and nothing else. One of the most common statements is the following assignment statement:


x = a + b;

Unlike in algebra, this statement does not mean that x is equal to a+b. Rather, this is read, “Assign the value of the sum of a and b to x,” or “Assign to x, a+b,” or “Set x equal to a plus b.”

This statement is doing two things. It is adding a and b together, and it is assigning the result to x using the assignment operator (=). Even though this statement is doing two things, it is one statement, and thus has one semicolon.

Note

The assignment operator assigns whatever is on the right side of the equal sign to whatever is on the left side.

Using Whitespace

Whitespace is the invisible characters such as tabs, spaces, and new lines. These are called “whitespace characters” because if they are printed on a piece of white paper, you only see the white of the paper.

Whitespace is generally ignored in statements. For example, the assignment statement previously discussed could be written as


x=a+b;

or as

Image

Although this last variation is perfectly legal, it is also perfectly foolish. Whitespace can be used to make your programs more readable and easier to maintain, or it can be used to create horrific and indecipherable code. In this, as in all things, C++ provides the power; you supply the judgment.

Blocks and Compound Statements

Any place you can put a single statement, you can put a compound statement, also called a block. A block begins with an opening brace ({) and ends with a closing brace (}).

Although every statement in the block must end with a semicolon, the block itself does not end with a semicolon, as shown in the following example:


{
     temp = a;
     a = b;
     b = temp;
}

This block of code acts as one statement and swaps the values in the variables a and b.

Image

Expressions

Anything that evaluates to a value is an expression in C++. An expression is said to return a value. Thus, the statement 3+2; returns the value 5, so it is an expression. All expressions are statements.

The myriad pieces of code that qualify as expressions might surprise you. Here are three examples:

Image

Assuming that PI is a constant created that is initialized to 3.14 and SecondsPerMinute is a constant equal to 60, all three of these statements are expressions.

The slightly more complicated expression


x = a + b;

not only adds a and b and assigns the result to x, but returns the value of that assignment (the value of x) as well. Thus, this assignment statement is also an expression.

As a note, any expression can be used on the right side of an assignment operator. This includes the assignment statement just shown. The following is perfectly legal in C++:


y = x = a + b;

This line is evaluated in the following order:

Add a to b.

Assign the result of the expression a + b to x.

Assign the result of the assignment expression x = a + b to y.

If a, b, x, and y are all integers, and if a has the value 9 and b has the value 7, both x and y will be assigned the value 16. This is illustrated in Listing 4.1.

Listing 4.1. Evaluating Complex Expressions


1:  #include <iostream>
2:  int main()
3:  {
4:     using std::cout;
5:     using std::endl;
6:
7:     int a=0, b=0, x=0, y=35;
8:     cout << "a: " << a << " b: " << b;
9:     cout << " x: " << x << " y: " << y << endl;
10:     a = 9;
11:     b = 7;
12:     y = x = a+b;
13:     cout << "a: " << a << " b: " << b;
14:     cout << " x: " << x << " y: " << y << endl;
15:     return 0;
16:  }

Image


a: 0 b: 0 x: 0 y: 35
a: 9 b: 7 x: 16 y: 16

Image

On line 7, the four variables are declared and initialized. Their values are printed on lines 8 and 9. On line 10, a is assigned the value 9. On line 11, b is assigned the value 7. On line 12, the values of a and b are summed and the result is assigned to x. This expression (x = a+b) evaluates to a value (the sum of a + b), and that value is, in turn, assigned to y. On lines 13 and 14, these results are confirmed by printing out the values of the four variables.

Working with Operators

An operator is a symbol that causes the compiler to take an action. Operators act on operands, and in C++ any expression can be an operand. In C++, several categories of operators exist. The first two categories of operators that you will learn about are

Assignment operators

• Mathematical operators

Assignment Operators

You saw the assignment operator (=) earlier. This operator causes the operand on the left side of the assignment operator to have its value changed to the value of the expression on the right side of the assignment operator. The expression


x = a + b;

assigns the value that is the result of adding a and b to the operand x.

l-values and r-values

An operand that legally can be on the left side of an assignment operator is called an l-value. That which can be on the right side is called (you guessed it) an r-value.

You should note that all l-values are r-values, but not all r-values are l-values. An example of an r-value that is not an l-value is a literal. Thus, you can write

x = 5;

but you cannot write

5 = x;

x can be an l-value or an r-value, 5 can only be an r-value.

Note

Constants are r-values. Because they cannot have their values changed, they are not allowed to be on the left side of the assignment operator, which means they can’t be l-values.

Mathematical Operators

A second category of operators is the mathematical operators. Five mathematical operators are addition (+), subtraction (), multiplication (*), division (/), and modulus (%).

Addition and subtraction work as you would expect: Two numbers separated by the plus or minus sign are added or subtracted. Multiplication works in the same manner; however, the operator you use to do multiplication is an asterisk (*). Division is done using a forward slash operator. The following are examples of expressions using each of these operators. In each case, the result is assigned to the variable result. The comments to the right show what the value of result would be

Image

Subtraction Troubles

Subtraction with unsigned integers can lead to surprising results if the result is a negative number. You saw something much like this yesterday, when variable overflow was described. Listing 4.2 shows what happens when you subtract a large unsigned number from a small unsigned number.

Listing 4.2. A Demonstration of Subtraction and Integer Overflow


1:  // Listing 4.2 - demonstrates subtraction and
2:  // integer overflow
3:  #include <iostream>
4:  
5:  int main()
6:  {
7:       using std::cout;
8:       using std::endl;
9:    
10:       unsigned int difference;
11:       unsigned int bigNumber = 100;
12:       unsigned int smallNumber = 50;
13:   
14:       difference = bigNumber - smallNumber;
15:       cout << "Difference is: " << difference;
16:
17:       difference = smallNumber - bigNumber;
18:       cout << " Now difference is: " << difference <<endl;
19:       return 0;
20:  }

Image

Difference is: 50
Now difference is: 4294967246

Image

The subtraction operator is invoked for the first time on line 14, and the result is printed on line 15, much as you might expect. The subtraction operator is called again on line 17, but this time a large unsigned number is subtracted from a small unsigned number. The result would be negative, but because it is evaluated (and printed) as an unsigned number, the result is an overflow, as described yesterday. This topic is reviewed in detail in Appendix C, “Operator Precedence.”

Integer Division and Modulus

Integer division is the division you learned when you were in elementary school. When you divide 21 by 4 (21 / 4), and you are doing integer division, the answer is 5 (with a remainder).

The fifth mathematical operator might be new to you. The modulus operator (%) tells you the remainder after an integer division. To get the remainder of 21 divided by 4, you take 21 modulus 4 (21 % 4). In this case, the result is 1.

Finding the modulus can be very useful. For example, you might want to print a statement on every 10th action. Any number whose value is 0 when you modulus 10 with that number is an exact multiple of 10. Thus 1 % 10 is 1, 2 % 10 is 2, and so forth, until 10 % 10, whose result is 0. 11 % 10 is back to 1, and this pattern continues until the next multiple of 10, which is 20. 20%10 = 0 again. You’ll use this technique when looping is discussed on Day 7, “More on Program Flow.”

FAQ

When I divide 5/3, I get 1. What is going wrong?

Answer: If you divide one integer by another, you get an integer as a result.

Thus, 5/3 is 1. (The actual answer is 1 with a remainder of 2. To get the remainder, try 5%3, whose value is 2.)

To get a fractional return value, you must use floating-point numbers (type float, double, or long double).

5.0 / 3.0 gives you a fractional answer: 1.66667.

If either the divisor or the dividend is a floating point, the compiler generates a floating-point quotient. However, if this is assigned to an l-value that is an integer, the value is once again truncated.

Combining the Assignment and Mathematical Operators

It is not uncommon to want to add a value to a variable and then to assign the result back into the same variable. If you have a variable myAge and you want to increase the value stored in it by two, you can write

Image

The first two lines create the myAge variable and a temporary variable. As you can see in the third line, the value in myAge has two added to it. The resulting value is assigned to temp. In the next line, this value is then placed back into myAge, thus updating it.

This method, however, is terribly convoluted and wasteful. In C++, you can put the same variable on both sides of the assignment operator; thus, the preceding becomes


myAge = myAge + 2;

which is much clearer and much better. In algebra, this expression would be meaningless, but in C++ it is read as “add two to the value in myAge and assign the result to myAge.”

Even simpler to write, but perhaps a bit harder to read is


myAge += 2;

This line is using the self-assigned addition operator (+=). The self-assigned addition operator adds the r-value to the l-value and then reassigns the result into the l-value. This operator is pronounced “plus-equals.” The statement is read “myAge plus-equals two.” If myAge had the value 24 to start, it would have 26 after this statement.

Self-assigned subtraction (-=), division (/=), multiplication (*=), and modulus (%=) operators exist as well.

Incrementing and Decrementing

The most common value to add (or subtract) and then reassign into a variable is 1. In C++, increasing a value by 1 is called incrementing, and decreasing by 1 is called decrementing. Special operators are provided in C++ to perform these actions.

The increment operator (++) increases the value of the variable by 1, and the decrement operator (––) decreases it by 1. Thus, if you have a variable, Counter, and you want to increment it, you would use the following statement:


Counter++;               // Start with Counter and increment it.

This statement is equivalent to the more verbose statement


Counter = Counter + 1;

which is also equivalent to the moderately verbose statement


Counter += 1;

Note

As you might have guessed, C++ got its name by applying the increment operator to the name of its predecessor language: C. The idea is that C++ is an incremental improvement over C.

Prefixing Versus Postfixing

Both the increment operator (++) and the decrement operator(––) come in two varieties: prefix and postfix. The prefix variety is written before the variable name (++myAge); the postfix variety is written after the variable name (myAge++).

In a simple statement, it doesn’t matter which you use, but in a complex statement when you are incrementing (or decrementing) a variable and then assigning the result to another variable, it matters very much.

The prefix operator is evaluated before the assignment; the postfix is evaluated after the assignment. The semantics of prefix is this: Increment the value in the variable and then fetch or use it. The semantics of postfix is different: Fetch or use the value and then increment the original variable.

This can be confusing at first, but if x is an integer whose value is 5 and using a prefix increment operator you write


int a = ++x;

you have told the compiler to increment x (making it 6) and then fetch that value and assign it to a. Thus, a is now 6 and x is now 6.

If, after doing this, you use the postfix operator to write


int b = x++;

you have now told the compiler to fetch the value in x (6) and assign it to b, and then go back and increment x. Thus, b is now 6, but x is now 7. Listing 4.3 shows the use and implications of both types.

Listing 4.3. A Demonstration of Prefix and Postfix Operators


1:  // Listing 4.3 - demonstrates use of
2:  // prefix and postfix increment and
3:  // decrement operators
4:  #include <iostream>
5:  int main()
6:  {
7:       using std::cout;
8:    
9:       int myAge = 39;     // initialize two integers
10:     int yourAge = 39;
11:     cout << "I am: " << myAge << " years old. ";
12:     cout << "You are: " << yourAge << " years old ";
13:     myAge++;            // postfix increment
14:     ++yourAge;          // prefix increment
15:     cout << "One year passes... ";
16:     cout << "I am: " << myAge << " years old. ";
17:     cout << "You are: " << yourAge << " years old ";
18:     cout << "Another year passes ";
19:     cout << "I am: " << myAge++ << " years old. ";
20:     cout << "You are: " << ++yourAge << " years old ";
21:     cout << "Let’s print it again. ";
22:     cout << "I am: " << myAge << " years old. ";
23:     cout << "You are: " << yourAge << " years old ";
24:     return 0;
25:  }

Image

Image

Image

On lines 9 and 10, two integer variables are declared, and each is initialized with the value 39. Their values are printed on lines 11 and 12.

On line 13, myAge is incremented using the postfix increment operator, and on line 14, yourAge is incremented using the prefix increment operator. The results are printed on lines 16 and 17, and they are identical (both 40).

On line 19, myAge is incremented as part of the printing statement, using the postfix increment operator. Because it is postfix, the increment happens after the printing, and so the value 40 is printed again, and then the myAge variable is incremented. In contrast, on line 20, yourAge is incremented using the prefix increment operator. Thus, it is incremented before being printed, and the value displays as 41.

Finally, on lines 22 and 23, the values are printed again. Because the increment statement has completed, the value in myAge is now 41, as is the value in yourAge.

Understanding Operator Precedence

In the complex statement


x = 5 + 3 * 8;

which is performed first, the addition or the multiplication? If the addition is performed first, the answer is 8 * 8, or 64. If the multiplication is performed first, the answer is 5 + 24, or 29.

The C++ standard does not leave the order random. Rather, every operator has a precedence value, and the complete list is shown in Appendix C. Multiplication has higher precedence than addition; thus, the value of the expression is 29.

When two mathematical operators have the same precedence, they are performed in left-to-right order. Thus,


x = 5 + 3 + 8 * 9 + 6 * 4;

is evaluated multiplication first, left to right. Thus, 8*9 = 72, and 6*4 = 24. Now the expression is essentially


x = 5 + 3 + 72 + 24;

Now, the addition, left to right, is 5 + 3 = 8; 8 + 72 = 80; 80 + 24 = 104.

Be careful with this. Some operators, such as assignment, are evaluated in right-to-left order!

In any case, what if the precedence order doesn’t meet your needs? Consider the expression


TotalSeconds = NumMinutesToThink + NumMinutesToType * 60

In this expression, you do not want to multiply the NumMinutesToType variable by 60 and then add it to NumMinutesToThink. You want to add the two variables to get the total number of minutes, and then you want to multiply that number by 60 to get the total seconds.

You use parentheses to change the precedence order. Items in parentheses are evaluated at a higher precedence than any of the mathematical operators. Thus, the preceding example should be written as:


TotalSeconds = (NumMinutesToThink + NumMinutesToType) * 60

Nesting Parentheses

For complex expressions, you might need to nest parentheses one within another. For example, you might need to compute the total seconds and then compute the total number of people who are involved before multiplying seconds times people:


TotalPersonSeconds = ( ( (NumMinutesToThink + NumMinutesToType) * 60) *
(PeopleInTheOffice + PeopleOnVacation) )

This complicated expression is read from the inside out. First, NumMinutesToThink is added to NumMinutesToType because these are in the innermost parentheses. Then, this sum is multiplied by 60. Next, PeopleInTheOffice is added to PeopleOnVacation. Finally, the total number of people found is multiplied by the total number of seconds.

This example raises an important related issue. This expression is easy for a computer to understand, but very difficult for a human to read, understand, or modify. Here is the same expression rewritten, using some temporary integer variables:


TotalMinutes = NumMinutesToThink + NumMinutesToType;
TotalSeconds = TotalMinutes * 60;
TotalPeople = PeopleInTheOffice + PeopleOnVacation;
TotalPersonSeconds = TotalPeople * TotalSeconds;

This example takes longer to write and uses more temporary variables than the preceding example, but it is far easier to understand. If you add a comment at the top to explain what this code does and change the 60 to a symbolic constant, you will have code that is easy to understand and maintain.

Image

The Nature of Truth

Every expression can be evaluated for its truth or falsity. Expressions that evaluate mathematically to zero return false; all others return true.

In previous versions of C++, all truth and falsity was represented by integers, but the ANSI standard introduced the type bool. A bool can only have one of two values: false or true.

Note

Many compilers previously offered a bool type, which was represented internally as a long int and, thus, had a size of four bytes. Now, ANSI-compliant compilers often provide a one-byte bool.

Evaluating with the Relational Operators

The relational operators are used to compare two numbers to determine whether they are equal or if one is greater or less than the other. Every relational statement evaluates to either true or false. The relational operators are presented later, in Table 4.1.

Table 4.1. The Relational Operators

Image

Note

All relational operators return a value of type bool, that is either true or false. In previous versions of C++, these operators returned either 0 for false or a nonzero value (usually 1) for true.

If the integer variable myAge has the value 45, and the integer variable yourAge has the value 50, you can determine whether they are equal by using the relational “equals” operator (==):


myAge == yourAge;  // is the value in myAge the same as in yourAge?

This expression evaluates to false because the variables are not equal. You can check to see if myAge is less than yourAge using the expression,


myAge < yourAge;  // is myAge less than yourAge?

which evaluates to true because 45 is less than 50.

Caution

Many novice C++ programmers confuse the assignment operator (=) with the equals operator (==). This can create a nasty bug in your program.

The six relational operators are equals (==), less than (<), greater than (>), less than or equal to (<=), greater than or equal to (>=), and not equals (!=). Table 4.1 shows each relational operator and a sample code use.

Image

The if Statement

Normally, your program flows along line-by-line in the order in which it appears in your source code. The if statement enables you to test for a condition (such as whether two variables are equal) and branch to different parts of your code, depending on the result.

The simplest form of an if statement is the following:


if (expression)
       statement;

The expression in the parentheses can be any expression, but it usually contains one of the relational expressions. If the expression has the value false, the statement is skipped. If it evaluates true, the statement is executed. Consider the following example:


if (bigNumber > smallNumber)
       bigNumber = smallNumber;

This code compares bigNumber and smallNumber. If bigNumber is larger, the second line sets its value to the value of smallNumber. If bigNumber is not larger than smallNumber, the statement is skipped.

Because a block of statements surrounded by braces is equivalent to a single statement, the branch can be quite large and powerful:


if (expression)
{
       statement1;
       statement2;
       statement3;
}

Here’s a simple example of this usage:


if (bigNumber > smallNumber)
{
       bigNumber = smallNumber;
       std::cout << "bigNumber: " << bigNumber << " ";
       std::cout << "smallNumber: " << smallNumber << " ";
}

This time, if bigNumber is larger than smallNumber, not only is it set to the value of smallNumber, but an informational message is printed. Listing 4.4 shows a more detailed example of branching based on relational operators.

Listing 4.4. A Demonstration of Branching Based on Relational Operators


1:  // Listing 4.4 - demonstrates if statement
2:  // used with relational operators
3:  #include <iostream>
4:  int main()
5:  {
6:       using std::cout;
7:       using std::cin;
8:  
9:       int MetsScore, YankeesScore;
10:     cout << "Enter the score for the Mets: ";
11:     cin >> MetsScore;
12:  
13:     cout << " Enter the score for the Yankees: ";
14:     cin >> YankeesScore;
15:  
16:     cout << " ";
17:  
18:     if (MetsScore > YankeesScore)
19:        cout << "Let’s Go Mets! ";
20:  
21:     if (MetsScore < YankeesScore)
22:     {
23:        cout << "Go Yankees! ";
24:     }
25:  
26:     if (MetsScore == YankeesScore)
27:     {
28:        cout << "A tie? Naah, can’t be. ";
29:        cout << "Give me the real score for the Yanks: ";
30:        cin >> YankeesScore;
31:  
32:        if (MetsScore > YankeesScore)
33:           cout << "Knew it! Let’s Go Mets!";
34:  
35:        if (YankeesScore > MetsScore)
36:           cout << "Knew it! Go Yanks!";
37:  
38:        if (YankeesScore == MetsScore)
39:           cout << "Wow, it really was a tie!";
40:     }
41:  
42:     cout << " Thanks for telling me. ";
43:     return 0;
44:  }

Image


Enter the score for the Mets: 10

Enter the score for the Yankees: 10

A tie? Naah, can’t be
Give me the real score for the Yanks: 8
Knew it! Let’s Go Mets!
Thanks for telling me.

Image

This program asks for the user to input scores for two baseball teams; the scores are stored in integer variables, MetsScore and YankeesScore. The variables are compared in the if statement on lines 18, 21, and 26.

If one score is higher than the other, an informational message is printed. If the scores are equal, the block of code that begins on line 27 and ends on line 40 is entered. The second score is requested again, and then the scores are compared again.

Note that if the initial Yankees’ score is higher than the Mets score, the if statement on line 18 evaluates as false, and line 19 is not invoked. The test on line 21 evaluates as true, and the statement on line 23 is invoked. Then, the if statement on line 26 is tested and this is false (if line 18 is true). Thus, the program skips the entire block, falling through to line 41.

This example illustrates that getting a true result in one if statement does not stop other if statements from being tested.

Note that the action for the first two if statements is one line (printing “Let’s Go Mets!” or “Go Yankees!”). In the first example (on line 19), this line is not in braces; a single line block doesn’t need them. The braces are legal, however, and are used on lines 22–24.

Avoiding Common Errors with if Statements

Many novice C++ programmers inadvertently put a semicolon after their if statements:


if(SomeValue < 10);    // Oops! Notice the semicolon!
   SomeValue = 10;

What was intended here was to test whether SomeValue is less than 10, and if so, to set it to 10, making 10 the minimum value for SomeValue. Running this code snippet shows that SomeValue is always set to 10! Why? The if statement terminates with the semicolon (the do-nothing operator).

Remember that indentation has no meaning to the compiler. This snippet could more accurately have been written as


if (SomeValue < 10)  // test
;  // do nothing
SomeValue = 10;  // assign

Removing the semicolon makes the final line part of the if statement and makes this code do what was intended.

To minimize the chances of this problem, you can always write your if statements with braces, even when the body of the if statement is only one line:


if (SomeValue < 10)
{
   SomeValue = 10;
};

Indentation Styles

Listing 4.4 shows one style of indenting if statements. Nothing is more likely to create a religious war, however, than to ask a group of programmers what is the best style for brace alignment. Although dozens of variations are possible, the following appear to be the most popular three:

Putting the initial brace after the condition and aligning the closing brace under the if to close the statement block:


if (expression){
     statements
}

• Aligning the braces under the if and indenting the statements:


if (expression)
{
    statements
}

• Indenting the braces and statements:


if (expression)
   {
   statements
   }

This book uses the middle alternative because it is easy to understand where blocks of statements begin and end if the braces line up with each other and with the condition being tested. Again, it doesn’t matter which style you choose, so long as you are consistent with it.

The else Statement

Often, your program needs to take one branch if your condition is true, or another if it is false. In Listing 4.4, you wanted to print one message (Let’s Go Mets!) if the first test (MetsScore > YankeesScore) evaluated true, and another message (Go Yankees!) if it evaluated false.

The method shown so far—testing first one condition and then the other—works fine but is a bit cumbersome. The keyword else can make for far more readable code:


if (expression)
       statement;
else
       statement;

Listing 4.5 demonstrates the use of the keyword else.

Listing 4.5. Demonstrating the else Keyword


1:  // Listing 4.5 - demonstrates if statement
2:  // with else clause
3:  #include <iostream>
4:  int main()
5:  {
6:       using std::cout;
7:       using std::cin;
8:    
9:       int firstNumber, secondNumber;
10:       cout << "Please enter a big number: ";
11:       cin >> firstNumber;
12:       cout << " Please enter a smaller number: ";
13:       cin >> secondNumber;
14:       if (firstNumber > secondNumber)
15:          cout << " Thanks! ";
16:       else
17:          cout << " Oops. The first number is not bigger!";
18:  
19:       return 0;
20:  }

Image


Please enter a big number: 10

Please enter a smaller number: 12
Oops. The first number is not bigger!

Image

The if statement on line 14 is evaluated. If the condition is true, the statement on line 15 is run and then program flow goes to line 18 (after the else statement). If the condition on line 14 evaluates to false, control goes to the else clause and so the statement on line 17 is run. If the else clause on line 16 was removed, the statement on line 17 would run regardless of whether the if statement was true.

Remember, the if statement ends after line 15. If the else was not there, line 17 would just be the next line in the program. You should also note that either or both of the if and the else statements could be replaced with a block of code in braces.

The if Statement

The syntax for the if statement is as follows:

Form 1


if (expression)
   statement;
next_statement;

If the expression is evaluated as true, the statement is executed and the program continues with the next_statement. If the expression is not true, the statement is ignored and the program jumps to the next_statement.

Remember that the statement can be a single statement ending with a semicolon or a block enclosed in braces.

Form 2


if (expression)
    statement1;
else
    statement2;
next_statement;

If the expression evaluates true, statement1 is executed; otherwise, statement2 is executed. Afterward, the program continues with the next_statement.

Example 1



if (SomeValue < 10)
  cout << "SomeValue is less than 10");
else
  cout << "SomeValue is not less than 10!");
cout << "Done." << endl;

Advanced if Statements

It is worth noting that any statement can be used in an if or else clause, even another if or else statement. Thus, you might see complex if statements in the following form:


if (expression1)
{
    if (expression2)
        statement1;
    else
    {
          if (expression3)
            statement2;
          else
            statement3;
    }
}
else
    statement4;

This cumbersome if statement says, “If expression1 is true and expression2 is true, execute statement1. If expression1 is true but expression2 is not true, then if expression3 is true execute statement2. If expression1 is true but expression2 and expression3 are false, then execute statement3. Finally, if expression1 is not true, execute statement4.” As you can see, complex if statements can be confusing!

Listing 4.6 gives an example of one such complex if statement.

Listing 4.6. A Complex, Nested if Statement


1:  // Listing 4.6 - a complex nested
2:  // if statement
3:  #include <iostream>
4:  int main()
5:  {
6:     // Ask for two numbers
7:       // Assign the numbers to bigNumber and littleNumber
8:       // If bigNumber is bigger than littleNumber,
9:       // see if they are evenly divisible
10:    // If they are, see if they are the same number
11:  
12:    using namespace std;
13:
14:    int firstNumber, secondNumber;
15:    cout << "Enter two numbers. First: ";
16:    cin >> firstNumber;
17:    cout << " Second: ";
18:    cin >> secondNumber;
19:    cout << " ";
20:
21:    if (firstNumber >= secondNumber)
22:    {
23:       if ( (firstNumber % secondNumber) == 0) // evenly divisible?
24:       {
25:          if (firstNumber == secondNumber)
26:             cout << "They are the same! ";
27:          else
28:             cout << "They are evenly divisible! ";
29:       }
30:       else
31:          cout << "They are not evenly divisible! ";
32:    }
33:    else
34:       cout << "Hey! The second one is larger! ";
35:    return 0;
36: }

Image


Enter two numbers.
First: 10

Second: 2
They are evenly divisible!

Image

Two numbers are prompted for one at a time, and then compared. The first if statement, on line 21, checks to ensure that the first number is greater than or equal to the second. If not, the else clause on line 33 is executed.

If the first if is true, the block of code beginning on line 22 is executed, and a second if statement is tested on line 23. This checks to see whether the first number divided by the second number yields no remainder. If so, the numbers are either evenly divisible or equal. The if statement on line 25 checks for equality and displays the appropriate message either way.

If the if statement on line 23 fails (evaluates to false), then the else statement on line 30 is executed.

Using Braces in Nested if Statements

Although it is legal to leave out the braces on if statements that are only a single statement, and it is legal to nest if statements, doing so can cause enormous confusion. The following is perfectly legal in C++, although it looks somewhat confusing:

Image

Remember, whitespace and indentation are a convenience for the programmer; they make no difference to the compiler. It is easy to confuse the logic and inadvertently assign an else statement to the wrong if statement. Listing 4.7 illustrates this problem.

Listing 4.7. A Demonstration of Why Braces Help Clarify Which else Statement Goes with Which if Statement


1:  // Listing 4.7 - demonstrates why braces
2:  // are important in nested if statements
3:  #include <iostream>
4:  int main()
5:  {
6:     int x;
7:     std::cout << "Enter a number less than 10 or greater than 100: ";
8:     std::cin >> x;
9:     std::cout << " ";
10:
11:     if (x >= 10)
12:        if (x > 100)
13:           std::cout << "More than 100, Thanks! ";
14:     else                            // not the else intended!
15:        std::cout << "Less than 10, Thanks! ";
16:
17:     return 0;
18:  }

Image


Enter a number less than 10 or greater than 100: 20

Less than 10, Thanks!

Image

The programmer intended to ask for a number less than 10 or greater than 100, check for the correct value, and then print a thank-you note.

When the if statement on line 11 evaluates true, the following statement (line 12) is executed. In this case, line 12 executes when the number entered is greater than 10. Line 12 contains an if statement also. This if statement evaluates true if the number entered is greater than 100. If the number is greater than 100, the statement on line 13 is executed, thus printing out an appropriate message.

If the number entered is less than 10, the if statement on line 11 evaluates false. Program control goes to the next line following the if statement, in this case line 16. If you enter a number less than 10, the output is as follows:


Enter a number less than 10 or greater than 100: 9

As you can see, there was no message printed. The else clause on line 14 was clearly intended to be attached to the if statement on line 11, and thus is indented accordingly. Unfortunately, the else statement is really attached to the if statement on line 12, and thus this program has a subtle bug.

It is a subtle bug because the compiler will not complain. This is a legal C++ program, but it just doesn’t do what was intended. Further, most of the times the programmer tests this program, it will appear to work. As long as a number that is greater than 100 is entered, the program will seem to work just fine. However, if you enter a number from 11 to 99, you’ll see that there is obviously a problem!

Listing 4.8 fixes the problem by putting in the necessary braces.

Listing 4.8. A Demonstration of the Proper Use of Braces with an if Statement


1:  // Listing 4.8 - demonstrates proper use of braces
2:  // in nested if statements
3:  #include <iostream>
4:  int main()
5:  {
6:     int x;
7:     std::cout << "Enter a number less than 10 or greater than 100: ";
8:     std::cin >> x;
9:     std::cout << " ";
10:
11:     if (x >= 10)
12:     {
13:        if (x > 100)

14:           std::cout << "More than 100, Thanks! ";
15:     }
16:     else                            // fixed!
17:        std::cout << "Less than 10, Thanks! ";
18:     return 0;
19:  }

Image


Enter a number less than 10 or greater than 100: 9
Less than 10, Thanks!

Image

The braces on lines 12 and 15 make everything between them into one statement, and now the else on line 16 applies to the if on line 11, as intended.

If the user types 9, the if statement on line 11 is true; however, the if statement on line 13 is false, so nothing would be printed. It would be better if the programmer put another else clause after line 14 so that errors would be caught and a message printed.

Tip

You can minimize many of the problems that come with if...else statements by always using braces for the statements in the if and else clauses, even when only one statement follows the condition.

if (SomeValue < 10){   SomeValue = 10;}else{   SomeValue = 25;};

Note

The programs shown in this book are written to demonstrate the particular issues being discussed. They are kept intentionally simple; no attempt is made to “bulletproof” the code to protect against user error. Ideally, in professional-quality code, every possible user error is anticipated and handled gracefully.

Using the Logical Operators

Often, you want to ask more than one relational question at a time. “Is it true that x is greater than y, and also true that y is greater than z?” A program might need to determine that both of these conditions are true—or that some other set of conditions is true—in order to take an action.

Imagine a sophisticated alarm system that has this logic: “If the door alarm sounds AND it is after 6:00 p.m. AND it is NOT a holiday, OR if it is a weekend, then call the police.” C++’s three logical operators are used to make this kind of evaluation. These operators are listed in Table 4.2.

Table 4.2. The Logical Operators

Image

The Logical AND Operator

A logical AND statement uses the AND operator to connect and evaluates two expressions. If both expressions are true, the logical AND statement is true as well. If it is true that you are hungry, AND it is true that you have money, THEN it is true that you can buy lunch. Thus,


if ( (x == 5) && (y == 5) )

evaluates true if both x and y are equal to 5, and it evaluates false if either one is not equal to 5. Note that both sides must be true for the entire expression to be true.

Note that the logical AND is two && symbols. A single & symbol is a different operator, which is discussed on Day 21, “What’s Next.”

The Logical OR Operator

A logical OR statement evaluates two expressions. If either one is true, the expression is true. If you have money OR you have a credit card, you can pay the bill. You don’t need both money and a credit card; you need only one, although having both is fine as well. Thus,


if ( (x == 5) || (y == 5) )

evaluates true if either x or y is equal to 5, or if both are equal to 5.

Note that the logical OR is two || symbols. A single | symbol is a different operator, which is discussed on Day 21.

The Logical NOT Operator

A logical NOT statement evaluates true if the expression being tested is false. Again, if the expression being tested is false, the value of the test is true! Thus,


if ( !(x == 5) )

is true only if x is not equal to 5. This is the same as writing


if (x != 5)

Short Circuit Evaluation

When the compiler is evaluating an AND statement, such as


if ( (x == 5) && (y == 5) )

the compiler evaluates the truth of the first statement (x==5), and if this fails (that is, if x is not equal to 5), the compiler does NOT go on to evaluate the truth or falsity of the second statement (y == 5) because AND requires both to be true.

Similarly, if the compiler is evaluating an OR statement, such as


if ( (x == 5) || (y == 5) )

if the first statement is true (x == 5), the compiler never evaluates the second statement (y == 5) because the truth of either is sufficient in an OR statement.

Although this might not seem important, consider the following example:


if ( (x == 5 )|| (++y == 3) )

If x is not equal to 5, then (++y == 3) is not evaluated. If you are counting on y to be incremented regardless, it might not happen.

Relational Precedence

Like all C++ expressions, the use of relational operators and logical operators each return a value: true or false. Like all expressions, they also have a precedence order (see Appendix C) that determines which relations are evaluated first. This fact is important when determining the value of statements such as the following:


if ( x > 5 &&  y > 5  || z > 5)

It might be that the programmer wanted this expression to evaluate true if both x and y are greater than 5 or if z is greater than 5. On the other hand, the programmer might have wanted this expression to evaluate true only if x is greater than 5 and if it is also true that either y is greater than 5 or z is greater than 5.

If x is 3, and y and z are both 10, the first interpretation is true (z is greater than 5, so ignore x and y), but the second is false (it isn’t true that x is greater than 5, and thus it doesn’t matter what is on the right side of the && symbol because both sides must be true).

Although precedence determines which relation is evaluated first, parentheses can both change the order and make the statement clearer:


if (  (x > 5)  && (y > 5 ||  z > 5) )

Using the values from earlier, this statement is false. Because it is not true that x is greater than 5, the left side of the AND statement fails, and thus the entire statement is false. Remember that an AND statement requires that both sides be true—something isn’t both “good tasting” AND “good for you” if it isn’t good tasting.

Tip

It is often a good idea to use extra parentheses to clarify what you want to group. Remember, the goal is to write programs that work and that are easy to read and to understand. Using parentheses help to clarify your intent and avoid errors that come from misunderstanding operator precedence.

More About Truth and Falsehood

In C++, zero evaluates to false, and all other values evaluate to true. Because an expression always has a value, many C++ programmers take advantage of this feature in their if statements. A statement such as

Image

can be read as “If x has a nonzero value, set it to 0.” This is a bit of a cheat; it would be clearer if written


if (x != 0)      // if x is not zero
    x = 0;

Both statements are legal, but the latter is clearer. It is good programming practice to reserve the former method for true tests of logic, rather than for testing for nonzero values.

These two statements also are equivalent:

Image

The second statement, however, is somewhat easier to understand and is more explicit if you are testing for the mathematical value of x rather than for its logical state.

Image

The Conditional (Ternary) Operator

The conditional operator (?:) is C++’s only ternary operator; that is, it is the only operator to take three terms.

The conditional operator takes three expressions and returns a value:


(expression1) ? (expression2) : (expression3)

This line is read as “If expression1 is true, return the value of expression2; otherwise, return the value of expression3.” Typically, this value is assigned to a variable. Listing 4.9 shows an if statement rewritten using the conditional operator.

Listing 4.9. A Demonstration of the Conditional Operator


1:  // Listing 4.9 - demonstrates the conditional operator
2:  //
3:  #include <iostream>
4:  int main()
5:  {
6:       using namespace std;
7:
8:       int x, y, z;
9:     cout << "Enter two numbers. ";
10:       cout << "First: ";
11:       cin >> x;
12:       cout << " Second: ";
13:       cin >> y;
14:       cout << " ";
15:  
16:       if (x > y)
17:          z = x;
18:       else
19:          z = y;
20:    
21:       cout << "After if test, z: " << z;
22:       cout << " ";
23:    
24:       z =  (x > y) ? x : y;
25:    
26:       cout << "After conditional test, z: " << z;
27:       cout << " ";
28:       return 0;
29:  }

Image


Enter two numbers.
First: 5

Second: 8

After if test, z: 8
After conditional test, z: 8

Image

Three integer variables are created: x, y, and z. The first two are given values by the user. The if statement on line 16 tests to see which is larger and assigns the larger value to z. This value is printed on line 21.

The conditional operator on line 24 makes the same test and assigns z the larger value. It is read like this: “If x is greater than y, return the value of x; otherwise, return the value of y.” The value returned is assigned to z. That value is printed on line 26. As you can see, the conditional statement is a shorter equivalent to the if...else statement.

Summary

In today’s lesson, you have learned what C++ statements and expressions are, what C++ operators do, and how C++ if statements work.

You have seen that a block of statements enclosed by a pair of braces can be used anywhere a single statement can be used.

You have learned that every expression evaluates to a value, and that value can be tested in an if statement or by using the conditional operator. You’ve also seen how to evaluate multiple statements using the logical operator, how to compare values using the relational operators, and how to assign values using the assignment operator.

You have explored operator precedence. And you have seen how parentheses can be used to change the precedence and to make precedence explicit, and thus easier to manage.

Q&A

Q   Why use unnecessary parentheses when precedence will determine which operators are acted on first?

A   It is true that the compiler will know the precedence and that a programmer can look up the precedence order. Using parentheses, however, makes your code easier to understand, and therefore easier to maintain.

Q   If the relational operators always return true or false, why is any nonzero value considered true?

A   This convention was inherited from the C language, which was frequently used for writing low-level software, such as operating systems and real-time control software. It is likely that this usage evolved as a shortcut for testing if all of the bits in a mask or variable are 0.

The relational operators return true or false, but every expression returns a value, and those values can also be evaluated in an if statement. Here’s an example:

if ( (x = a + b) == 35 )

This is a perfectly legal C++ statement. It evaluates to a value even if the sum of a and b is not equal to 35. Also note that x is assigned the value that is the sum of a and b in any case.

Q   What effect do tabs, spaces, and new lines have on the program?

A   Tabs, spaces, and new lines (known as whitespace) have no effect on the program, although judicious use of whitespace can make the program easier to read.

Q   Are negative numbers true or false?

A   All nonzero numbers, positive and negative, are true.

Workshop

The Workshop provides quiz questions to help you solidify your understanding of the material covered and exercises to provide you with experience in using what you’ve learned. Try to answer the quiz and exercise questions before checking the answers in Appendix D, and be certain that you understand the answers before continuing to tomorrow’s lesson on functions.

Quiz

1. What is an expression?

2. Is x = 5 + 7 an expression? What is its value?

3. What is the value of 201 / 4?

4. What is the value of 201 % 4?

5. If myAge, a, and b are all int variables, what are their values after


myAge = 39;
a = myAge++;
b = ++myAge;

6. What is the value of 8+2*3?

7. What is the difference between if(x = 3) and if(x == 3)?

8. Do the following values evaluate true or false?

a. 0

b. 1

c. –1

d. x = 0

e. x == 0 // assume that x has the value of 0

Exercises

1. Write a single if statement that examines two integer variables and changes the larger to the smaller, using only one else clause.

2. Examine the following program. Imagine entering three numbers, and write what output you expect.


1:   #include <iostream>
2:   using namespace std;
3:   int main()
4:   {
5:        int a, b, c;
6:        cout << "Please enter three numbers ";
7:        cout << "a: ";
8:        cin >> a;
9:        cout << " b: ";
10:       cin >> b;
11:       cout << " c: ";
12:       cin >> c;
13:
14:       if (c = (a-b))
15:            cout << "a: " << a << " minus b: " << b <<
16:                               _" equals c: " << c;

17:       else
18:            cout << "a-b does not equal c: ";
19:     return 0;
20:  }

3. Enter the program from Exercise 2; compile, link, and run it. Enter the numbers 20, 10, and 50. Did you get the output you expected? Why not?

4. Examine this program and anticipate the output:


1:     #include <iostream>
2:     using namespace std;
3:     int main()
4:     {
5:          int a = 2, b = 2, c;
6:          if (c = (a-b))
7:               cout << "The value of c is: " << c;
8:          return 0;
9:     }

Enter, compile, link, and run the program from Exercise 4. What was the output? Why?

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.26.138