Control Statements

Until this point in the book, statements have been executed in sequence. The flow of control in a C++ program is linear; it may pass to a function and back, but it always passes through each statement. Often you need to make decisions and you need to repeat actions. These are the basic reasons for control statements.

The if-else Statement

Programs often need to make decisions. For example, if a student scores less than a certain required minimum, action has to be taken; if an account is overdrawn more than a prescribed number of days, bills need to be sent out and interest rates raised. The C++ if-else statement handles these types of decisions:

;> int mark = 49;
;> if (mark >= 50) cout << "pass
";
;> else cout << "fail
";
fail
;>

This statement consists of three parts:

  • A condition, which can be any Boolean (or integer) expression enclosed in parentheses

  • A statement that is executed if the condition is true

  • An (optional) else, followed by a statement that is executed if the condition is false

Pascal programmers should note that there is always a semicolon after the if part. Not every if statement has an else, as in the following example:


;> const double MAX_OVERDRAFT = 5000;
;> void check_account (double overdraft) {
;1>  cout << "Overdraft is " << overdraft;
;1>  if (overdraft > MAX_OVERDRAFT)
;1>     cout << " overdrawn by " << overdraft – MAX_OVERDRAFT;
;1>  cout << endl;
;1> }
;> check_account(4000);
Overdraft is 4000.
;> check_account(6000);
Overdrarft is 6000. overdrawn by 1000.

The warning about the overdraft happens only if it is excessive. (Incidentally, note in this example how you can split up a line of output over several statements. Output streams, like input streams, are not line based, which is why you need endl.)

Generally speaking, you can put any valid C++ statement after if. The statements controlled by the if-else statement can themselves be if-else statements. This is a very common pattern, which is commonly used where there are multiple choices to be made. Save the following as mult-if.cpp in Notepad, and load it using the #l command. You can then test it as before:


// mult-if.cpp
string test_if (int mark)
{
  string symbol;
  if (mark < 50) symbol = "F";
  else if (mark >= 50 && mark < 55) symbol = "E";
  else if (mark >= 55 && mark < 60) symbol = "D";
  else if (mark >= 60 && mark < 65) symbol = "C";
  return symbol;
}
;> #l mult-if.cpp
;> test_if(55);
(string) 'D'

Experimenting with if statements with UnderC reveals curious behavior. Say you type an if statement that should execute, but nothing happens until you type another statement. This happens because the compiler is looking ahead to see whether an else is forthcoming. It's easy to force this by adding an extra semicolon, creating an empty statement, as in the following example:

;> if (20 > 10) cout << "yeah!
"; ;
yeah!

CAUTION

The condition of an if statement might be just about any C++ expression that could possibly make sense as a bool or an integer. Java insists that it must be a bool, which is a good attitude to take in C++ as well. Remember that the assignment operator returns a value, which means that the following code is valid C++: n = 1 assigns 1 to n, and because the value 1 of that expression is nonzero, the condition is true. It is very easy to confuse == with =! Many compilers (like BCC55) will give you a warning about 'possibly incorrect assignment'.

;> int n = 2;
;> if (n = 1) cout << "was one!
"; ;
was one!


Blocks

You have previously encountered blocks in function definitions; the statements between braces ({}) form a block. Blocks are used to collect several statements together, and they may themselves contain blocks. Blocks are often controlled by if statements, as in the following example:


;> double a = 1, c = 0;
;> if (a > 0) {
;1>  double b = 2*a;
;1>  cout << "b is " << b << endl;
;1>  c = a – 1;
;1> }
 b is 2
;> b;
CON 3: Parse Error
CON 3: Cannot find 'b'

The interpreter prompt changes to show how deep the block level is at the moment. A declaration is a statement, so blocks can contain declarations, but these declarations are private to that block.

The while and do-while Statements

Programming any language becomes much more entertaining when statements can be repeatedly executed in a loop. Loop means that the flow of control jumps (or loops) back while some condition is true, as in the following example, which demonstrates the while statement. A while statement is similar to an if statement; there is a condition in parentheses followed by a controlled statement. The controlled statement is executed if the condition is true but will continue to be executed until that condition is false. The while statement followed by the controlled statement is often called a while loop:


;> int k = 0;
;> while (k < 10) k = k + 1;
;> k;
(int) k = 10

The controlled statement k = k + 1 executes 10 times, until the condition fails, because k was no longer less than 10. Incrementing a variable like this isn't good style in C or C++, however. Let's watch this loop in action again, this time using the postfix increment operator ++ (which returns the value of k before it is incremented):

;> k
							=
							0;
;> while (k < 4) cout << k++ << endl;
0
1
2
3
;> k;
(int) k = 4

The while statement can control any kind of statement, but it is especially used with blocks. The while statement is not executed if the condition is false at the beginning. There is another form of while loop in which the statement is always executed at least once: the do-while loop. The following function reads and sums numbers from a file until the end of the file:


int sum_file(string file)
 {
  ifstream in;
  in.open(file.c_str());
  int val=0,sum = 0;
  do {
    sum += val;
    in >> val;
  }   while (! in.eof());
  in.close();
  return sum;
 }

NOTE

The eof() method usually returns false, so ! in.eof() is true.


The problem with using a while loop here is that we must not use the value if the EOF becomes true, which means we have gone beyond the EOF, and the value is not meaningful (it is usually the last value read, but that's accidental). Replace the do-while with the following loop and note that it appears to count the last number twice:

while (! in.eof()) {
  in >> val;        // get the value
  sum += val;       // could be EOF at this point!
}

A much more convenient method is to use the result of the read operation itself, which is nonzero unless it is past the end of the file:

while (in >> val)
   sum += val;

The for Statement

It is common to want to use some statements a certain number of times or take a variable (that is, a loop counter) from a start to a finish value. The while statement is not ideal for this job because you must initialize the variable separately and remember to increment it each time, both of which are tasks that you can easily get wrong. The initial value of the variable may be anything, and if you don't increment it, the loop happily goes on forever—it is an endless loop—because the condition is always true. The for statement is designed to make these kinds of loops easier and less error-prone. It has three parts, separated by semicolons: an initialization, a condition, and an operation that happens on each iteration. The following is the simplest form of the for statement, and you will learn to type it in your sleep:


;> for(k = 0; k < 4; k++) cout << k << endl;
0
1
2
3
;>
;> k
							=
							0;
(int) 0
;> while (k < 4) {
;1> cout << k << endl;
;1> k++;
;1> }
0
1
2
3

The first part of this for statement is executed once in the beginning; the second part is executed before the controlled statement; and the third part is executed after the controlled statement. Like a while statement, the for statement is not executed if the condition is initially false. In this example, the for loop is completely equivalent to the while loop, which is more complicated (because it needs a block). With a while statement, it is particularly easy to forget to increment the counter at the end, especially if there are many statements in the block.

The for statement does not trip off the tongue (or the fingers) as easily as BASIC's for loop. It is the ugliest way to get from 0 to n-1, but it is very flexible. It automatically goes from 0 to n-1, which is the way C++ prefers to count. You can declare variables in the initialization part. The following example sums the integers from 0 to 9:


;> int sum = 0;
;> for(int j = 0; j < 10; j++) sum += j;
;> sum;
(int) 45
;> j;
CON 6: Cannot find 'j'

In this example, note the shortcut addition operator. Any variables (here j) declared in the initialization part are visible only within the loop. So we get an error trying to access j outside the loop. The third section of a for statement is usually a plain increment (like j++) but it can be any expression. A for loop can go backward or go forward with a skip value, as in the following example:


;> for(k=3; k > 0; k—) cout << k << endl;
3
2
1
;> sum = 0;  // this will sum the even numbers up to (and including) 20
;> for (k=0; k <= 20; k+=2)  sum += k;
						

The for statement can control any statement, including another for statement. Therefore, you can use for to write nested loops, as in the following example:


;> for(int i = 0; i < 3; i++)
;1}  for(int j = 0; j < 3; j++)
;2}    if (i > j) cout << '(' << i << ',' << j << ")
";;
(1,0)
(2,0)
(2,1)

The loop variable does not have to be an integer, unlike in most other languages. In the following example, you vary a float variable and print out a small table of trigonometric functions. The shorthand assignment-with-addition operator (+=) is very convenient for incrementing x by a small amount:


for(float x = 0; x < 1.0; x += 0.1)
  cout << x << ' ' << sin(x) << endl;
0.000000 0.000000
0.100000 0.099833
0.200000 0.198669
0.300000 0.295520
0.400000 0.389418
0.500000 0.479426
0.600000 0.564642
0.700000 0.644218
0.800000 0.717356
0.900000 0.783327
1.000000 0.841471

The C++ for statement takes some getting used to, but it is very powerful for expressing many different kinds of loops.

The switch Statement

It is common to have a number of actions that are controlled by a set of values. Because it can be clumsy to use multiple if-else statements, C++ offers the switch statement. Within a switch block there are case labels for each value, followed by statements that will be executed. These are usually followed by a break statement, which explicitly forces the flow of control out of the block. There is a special-case label called default, which acts rather like an else statement.


void suburb(int prefix)
{
  switch(prefix) {
  case 728:
    cout << "Melville";
    break;
  case 482:
    cout << "Parktown";
    break;
  case 648:
  case 487:
    cout << "Yeoville";
    break;
  default:
    cout << "*Unrecognized*";
    break;
  }
  cout << endl;
}

This example shows how you handle cases where the action is triggered by more than one value. The flow of execution jumps to the case label, and then it falls through to the next label. If you don't put in a break, execution keeps going through every statement. In the following example, if l is 1 then both cases are executed.

;> switch(1) {
;>  case 1:  cout << "one ";
;>  case 2:  cout << "two ";
;> }
one two

You need to be careful with switch statements because they do not work like equivalent statements in other languages. At first, you may find it easy to forget the break. Even experienced programmers get their breaks mixed up; one of the most expensive bugs ever took out millions of telephones in the eastern United States, and it was due to a misplaced break.

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

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