Control Flow Statements, Continued

With the additional coverage of Boolean expressions, it's time to consider more of the control flow statements supported by C#. As indicated in the introduction, many of these statements will be familiar to experienced programmers, so you can skim this section for information specific to C#. Note in particular the foreach loop, as this may be new to many programmers.

The while and do/while Loops

Until now, you have learned how to write programs that do something only once. However, one of the important capabilities of the computer is that it can perform the same operation multiple times. In order to do this, you need to create an instruction loop. The first instruction loop I will discuss is the while loop. The general form of the while statement is as follows:

while(boolean-expression )  statement

The computer will repeatedly execute statement as long as Boolean-expression evaluates to true. If the statement evaluates to false, then code execution continues at the line following statement. The Fibonacci calculator shown in Listing 3.40 demonstrates this.

Listing 3.40. while Loop Example

 class FibonacciCalculator {   static void Main()   {      decimal current;      decimal previous;      decimal temp;      decimal input;      System.Console.Write("Enter a positive integer:");      // decimal.Parse convert the ReadLine to a decimal.      input = decimal.Parse(System.Console.ReadLine());      // Initialize current and previous to 1, the first      // two numbers in the Fibonacci series.       current = previous = 1;      // While the current Fibonacci number in the series is      // less than the value input by the user.      while(current <= input)                                                      {                                                                                temp = current;                                                              current = previous + current;                                                previous = temp;                                                         }                                                                            System.Console.WriteLine(          "The Fibonacci number following this is {0}",          current);     } }

A Fibonacci number is a member of the Fibonacci series, which includes all numbers that are the sum of the previous two numbers in the series, beginning with 1 and 1. In Listing 3.40, you prompt the user for an integer. Then you use a while loop to find the Fibonacci number that is greater than the number the user entered.

Beginner Topic: When to Use a while Loop

The remainder of this chapter considers other types of statements that cause a block of code to execute repeatedly. It is important to understand which loop construct to select. You use a while construct to iterate while the condition evaluates to true. A for loop is used most appropriately whenever the number of repetitions is counting from 0 to n. A do/while is similar to a while loop, except that it will always loop at least once.

The do/while loop is very similar to the while loop, except that it is used when the number of repetitions is from 1 to n and n is indeterminate when iterating begins. This pattern occurs most commonly when repeatedly prompting a user for input. Listing 3.41 is taken from the tic-tac-toe program.

Listing 3.41. do/while Loop Example

// Repeatedly request player to move until they // enter a valid position on the board. do {  valid = false;  // Request a move from the current player.  System.Console.Write(        "\nPlayer {0}: Enter move:", currentPlayer);  input = System.Console.ReadLine();  // Check the current player's input.  // ... } while (!valid);

In Listing 3.41, you always initialize valid to false at the beginning of each iteration, or loop repetition. Next, you prompt and retrieve the number the user input. Although not shown here, you then check whether the input was correct, and if it was, you assign valid equal to TRue. Since the code uses a do/while statement rather than a while statement, the user will be prompted for input at least once.

The general form of the do/while loop is as follows:

do   statement while(boolean-expression );

As with all the control flow statements, the code blocks are not part of the general form. However, a code block is generally used in place of a single statement in order to allow multiple statements.

The for loop

Increment and decrement operators are frequently used within a for loop. The for loop iterates a code block until a specified condition is reached in a way similar to the while loop. The difference is that the for loop has built-in syntax for initializing, incrementing, and testing the value of a counter.

Listing 3.42 shows the for loop used to display an integer in binary form. The results of this listing appear in Output 3.21.

Listing 3.42. Using the for Loop

public class BinaryConverter {  public static void Main()     {        const int size = 64;        ulong value;        char bit;        System.Console.Write ("Enter an integer: ");        // Use long.Parse() so as to support negative numbers        // Assumes unchecked assignment to ulong.        value = (ulong)long.Parse(System.Console.ReadLine());        // Set initial mask to 100....        ulong mask = 1ul << size - 1;        for (int count = 0; count < size; count++)       {         bit = ((mask & value) > 0) ? '1': '0';         System.Console.WriteLine(bit);         // Shift mask one location over to the right         mask >>= 1;       }     } }

Output 3.21.

Enter an integer: -42 1111111111111111111111111111111111111111111111111111111111010110

Listing 3.42 performs a bit mask 64 times, once for each bit in the number. The for loop declares and initializes the variable count, escapes once the count reaches 64, and increments the count during each iteration. Each expression within the for loop corresponds to a statement. (It is easy to remember that the separation character between expressions is a semicolon and not a comma, because each expression is a statement.)

You write a for loop generically as follows:

for(initial; boolean-expression; loop)  statement

Here is a breakdown of the for loop.

  • The initial expression performs operations that precede the first iteration. In Listing 3.42, it declares and initializes the variable count. The initial expression does not have to be a declaration of a new variable. It is possible, for example, to declare the variable beforehand and simply initialize it in the for loop. Variables declared here, however, are bound within the scope of the for statement.

  • The boolean-expression portion of the for loop specifies an end condition. The loop exits when this condition is false in a manner similar to the while loop's termination. The for loop will repeat only as long as boolean-expression evaluates to true. In the preceding example, the loop exits when count increments to 64.

  • The loop expression executes after each iteration. In the preceding example, count++ executes after the right shift of the mask (mask >>= 1), but before the Boolean expression is evaluated. During the 64th iteration, count increments to 64, causing boolean-expression to be false and, therefore, terminating the loop. Because each expression can be thought of as a separate statement, each expression in the for loop is separated by a semicolon.

  • The statement portion of the for loop is the code that executes while the conditional expression remains true.

If you wrote out each for loop execution step in pseudocode without using a for loop expression, it would look like this:

  1. Declare and initialize count to 0.

  2. Verify that count is less than 64.

  3. Calculate bit and display it.

  4. Shift the mask.

  5. Increment count by one.

  6. If count<64, then jump back to line 3.

The for statement doesn't require any of the elements between parentheses. for(;;){ ... } is perfectly valid, assuming there is still a means to escape from the loop. Similarly, the initial and loop expressions can be a complex expression involving multiple subexpressions, as shown in Listing 3.43.

Listing 3.43. for Loop Using Multiple Expressions

for(int x=0, y=5; ((x<=5) && (y>=0)); y, x++) {       System.Console.Write("{0}{1}{2}\t",          x, (x>y? '>' : '<'), y); }

The results of Listing 3.43 appear in Output 3.22.

Output 3.22.

0<5 1<4 2<3 3>2 4>1 5>0

In this case, the comma behaves exactly as it does in a declaration statement, one that declares and initializes multiple variables. However, programmers should avoid complex expressions like this one because they are difficult to read and understand.

Generically, you can write the for loop as a while loop, as shown here:

initial; while(boolean-expression) {  statement;  loop; }

Beginner Topic: Choosing between for and while Loops

Although you can use the two statements interchangeably, generally you would use the for loop whenever there is some type of counter, and the total number of iterations is known when the loop is initialized. In contrast, you would typically use the while loop when iterations are not based on a count or when the number of iterations is indeterminate when iterating commences.

The foreach Loop

The last loop statement within the C# language is foreach. foreach is designed to iterate through a collection of items, setting an identifier to represent each item in turn. During the loop, operations may be performed on the item. One feature of the foreach loop is that it is not possible to accidentally miscount and iterate over the end of the collection.

The general form of the foreach statement is as follows:

foreach(type identifier in collection)  statement;

Here is a breakdown of the foreach statement.

  • type is used to declare the data type of the identifier for each item within the collection.

  • identifier is a read-only variable into which the foreach construct will automatically assign the next item within the collection. The scope of the identifier is limited to the foreach loop.

  • collection is an expression, such as an array, representing multiple items.

  • statement is the code that executes for each iteration within the foreach loop.

Consider the foreach loop in the context of the simple example shown in Listing 3.44.

Listing 3.44. Determining Remaining Moves Using the foreach Loop

class TicTacToe      // Declares the TicTacToe class. {    static void Main() // Declares the entry point of the program.    {       // Hardcode initial board as follows       // ---+---+---       // 1 | 2 | 3       // ---+---+---       // 4 | 5 | 6       // ---+---+---       // 7 | 8 | 9       // ---+---+---       char[] cells = {           '1', '2', '3', '4', '5', '6', '7', '8', '9'    };    System.Console.Write(          "The available moves are as follows: ");    // Write out the initial available moves    foreach (char cell in cells)                                                 {                                                                             if (cell != 'O' & & cell != 'X')                                             {                                                                             System.Console.Write("{0} ", cell);                                         }                                                                           }                                                                           } }

Output 3.23 shows the results of Listing 3.44.

Output 3.23.

The available moves are as follows: 1 2 3 4 5 6 7 8 9

When the execution engine reaches the foreach statement, it assigns to the variable cell the first item in the cells arrayin this case, the value '1'. It then executes the code within the foreach statement block. The if statement determines whether the value of cell is 'O' or 'X'. If it is neither, then the value of cell is written out to the console. The next iteration then assigns the next array value to cell, and so on.

It is important to note that the compiler prevents modification of the identifier variable (cell) during the execution of a foreach loop.

Beginner Topic: Where the switch Statement Is More Appropriate

Sometimes you might compare the same value in several continuous if statements, as shown with the input variable in Listing 3.45.

Listing 3.45. Checking the Player's Input with an if Statement

// ... bool valid = false; // Check the current player's input. if( (input == "1") ||  (input == "2") ||  (input == "3") ||  (input == "4") ||  (input == "5") ||  (input == "6") ||  (input == "7") ||  (input == "8") ||  (input == "9") ) {     // Save/move as the player directed.     // ...     valid = true; } else if( (input == "") || (input == "quit") ) {      valid = true; } else {      System.Console.WriteLine(        "\nERROR: Enter a value from 1-9. "       + "Push ENTER to quit"); } // ...

This code validates the text entered to ensure it is a valid tic-tac-toe move. If the value of input were 9, for example, the program would have to perform nine different evaluations. It would be preferable to jump to the correct code after only one evaluation. To enable this, you use a switch statement.

The switch Statement

Given a variable to compare and a list of constant values to compare against, the switch statement is simpler to read and code than the if statement. The switch statement looks like this:

switch(governing-typeexpression) {      [case constant:         statement jump expression]          [default:  statement  jump expression] }

Here is a breakdown of the switch statement.

  • governing-type-expression returns a value that is compatible with the governing types. Allowable governing data types are sbyte,byte, short, ushort, int, uint, long, ulong, char, string, and an enum-type (covered in Chapter 8).

  • constant is any constant expression compatible with the data type of the governing type.

  • statement is one or more statements to be executed when the governing type expression equals the constant value.

  • jump expression is a jump statement such as a break or goto statement. If the switch statement appears within a loop, then continue is also allowed.

A switch statement must have at least one case statement or a default statement. In other words, switch(x){} is not valid.

Listing 3.46, with a switch statement, is semantically equivalent to the series of if statements in Listing 3.45.

Listing 3.46. Replacing the if Statement with a switch Statement

static bool ValidateAndMove(   int[] playerPositions, int currentPlayer, string input) {  bool valid = false;  // Check the current player's input.  switch (input)  {   case "1" :   case "2" :   case "3" :   case "4" :   case "5" :   case "6" :   case "7" :   case "8" :   case "9" :     // Save/move as the player directed.      ...      valid = true;      break;   case "" :   case "quit" :     valid = true;     break;   default :      // If none of the other case statements      // is encountered then the text is invalid.      System.Console.WriteLine(        "\nERROR: Enter a value from 1-9. "       + "Push ENTER to quit");     break;  }  return valid; }

In Listing 3.46, input is the governing type expression. Since input is a string, all of the constants are strings. If the value of input is 1, 2, ... 9, then the move is valid and you change the appropriate cell to match that of the current user's token (X or O). Once execution encounters a break statement, it immediately jumps to the statement following the switch statement.

The next portion of the switch looks for "" or "quit", and sets valid to TRue if input equals one of these values. Ultimately, the default label is executed if no prior case constant was equivalent to the governing type.

There are several things to note about the switch statement.

  • Placing nothing within the switch block will generate a compiler warning, but the statement will still compile.

  • default does not have to appear last within the switch statement. case statements appearing after default are evaluated.

  • When you use multiple constants for one case statement, they should appear consecutively, as shown in Listing 3.46.

  • The compiler requires a jump statement (usually a break).

Language Contrast: C++switch Statement Fallthrough

Unlike C++, C# does not allow a switch statement to fall through from one case block to the next if the case includes a statement. A jump statement is always required following the statement within a case. The C# founders believed it was better to be explicit and require the jump expression in favor of code readability. If programmers want to use a fall-through semantic, they may do so explicitly with a goto statement, as demonstrated in the section The goto Statement, later in this chapter.

Essential C# 2.0
Essential C# 2.0
ISBN: 0321150775
EAN: 2147483647
Year: 2007
Pages: 185 © 2008-2017.
If you may any questions please contact us: