Team LiB   Previous Section   Next Section

6.3 Iteration (Looping) Statements

There are many situations in which you will want to do the same thing again and again, perhaps slightly changing a value each time you repeat the action. This is called iteration or looping. Typically, you'll iterate (or loop) over a set of items, taking the same action on each. This is the programming equivalent of an assembly line. On an assembly line, you might take a hundred car bodies and put a windshield on each one as it comes by. In an iterative program, you might work your way through a collection of text boxes on a form, retrieving the value from each in turn and using those values to update a database.

C# provides an extensive suite of iteration statements, including for and while, and also do...while and foreach loops. You can also create a loop by using the goto statement. The remainder of this chapter considers the use of goto, for, while, and do...while. However, you'll have to wait until Chapter 15 to learn more about foreach.

6.3.1 Creating Loops with goto

The goto statement was used previously as an unconditional branch in a switch statement. Its more common usage, however, is to create a loop. In fact, the goto statement is the seed from which all other looping statements have been germinated. Unfortunately, it is a semolina seed, producer of spaghetti code and endless confusion.

Programs that use goto statements outside of switch blocks jump around a great deal. Goto can cause your method to loop back and forth in ways that are difficult to follow.

If you were to try to draw the flow of control in a program that makes extensive use of goto statements, the resulting morass of intersecting and overlapping lines might look like a plate of spaghetti — hence the term "spaghetti code." Spaghetti code is a contemptuous epithet; no one wants to write spaghetti code.

Most experienced programmers properly shun the goto statement, but in the interest of completeness, here's how you use it:

  1. Create a label.

  2. goto that label.

The label is an identifier followed by a colon. You place the label in your code, and then you use the goto keyword to jump to that label. The goto command is typically tied to an if statement, as illustrated in Example 6-10.

Example 6-10. Using goto
using System;
public class Tester
{

   public static void Main()
   {
      int counterVariable = 0;

      repeat:  // the label

      Console.WriteLine(
       "counterVariable: {0}",counterVariable);
      
      // increment the counter
      counterVariable++; 

      if (counterVariable < 10)
        goto repeat;  // the dastardly deed
   }
}
Output:
counterVariable: 0
counterVariable: 1
counterVariable: 2
counterVariable: 3
counterVariable: 4
counterVariable: 5
counterVariable: 6
counterVariable: 7
counterVariable: 8
counterVariable: 9

This code is not terribly complex; you've used only a single goto statement. However, with multiple such statements and labels scattered through your code, tracing the flow of execution becomes very difficult.

It was the phenomenon of spaghetti code that led to the creation of alternatives, such as the while loop.

6.3.2 The while Loop

The semantics of the while loop are "while this condition is true, do this work." The syntax is:

while (boolean expression) statement

As usual, a Boolean expression is any statement that evaluates to true or false. The statement executed within a while statement can of course be a block of statements within braces. Example 6-11 illustrates the use of the while loop.

Example 6-11. The while loop
using System;
public class Tester
{
    public static void Main()
    {
        int counterVariable = 0;

        // while the counter variable is less than 10
        // print out its value
        while (counterVariable < 10) 
        { 
            Console.WriteLine("counterVariable: {0}",counterVariable); 
            counterVariable++; 
        } 
    }
}
 Output:
counterVariable: 0
counterVariable: 1
counterVariable: 2
counterVariable: 3
counterVariable: 4
counterVariable: 5
counterVariable: 6
counterVariable: 7
counterVariable: 8
counterVariable: 9

The code in Example 6-11 produces results identical to the code in Example 6-10, but the logic is a bit clearer. The while statement is nicely self-contained, and it reads like an English sentence: "while counterVariable is less than 10, print this message and increment counterVariable."

The value of counterVariable is incremented (increased by 1) with the increment operator (++).

counterVariable++; //increment counterVariable

This operator is discussed in detail in Chapter 7.

Notice that the while loop tests the value of counterVariable before entering the loop. This ensures that the loop will not run if the condition tested is false; thus if counterVariable is initialized to 11, the loop will never run.

6.3.3 The do . . . while Loop

There are times when a while loop might not serve your purpose. In certain situations, you might want to reverse the semantics from "run while this is true" to the subtly different "do this, while this condition remains true." In other words, take the action, and then, after the action is completed, check the condition. Such a loop will always run at least once.

To ensure that the action is taken before the condition is tested, use a do...while loop:

do statement while (boolean-expression);

The syntax is to write the keyword do, followed by your statement (or block), the while keyword, and the condition to test in parentheses. End the statement with a semicolon.

Example 6-12 rewrites Example 6-11 to use a do...while loop.

Example 6-12. The do...while loop
using System;
public class Tester
{
    public static void Main()
    {
        int counterVariable = 11;

        // display the message and then test that the value is 
        // less than 10
        do 
        {
            Console.WriteLine("counterVariable: {0}",counterVariable);
            counterVariable++;
        } while (counterVariable < 10);
    }
}

In Example 6-12, counterVariable is initialized to 11 and the while test fails, but only after the body of the loop has run once.

6.3.4 The for Loop

A careful examination of the while loop in Example 6-11 reveals a pattern often seen in iterative statements: initialize a variable (counterVariable=0), test the variable (counterVariable<10), execute a series of statements, and increment the variable (counterVariable++). The for loop allows you to combine all these steps in a single statement. You write a for loop with the keyword for, followed by the for header, using the syntax:

for ([initializers]; [expression]; [iterators]) statement

The first part of the header is the initializers, in which you initialize a variable. The second part is the Boolean expression to test. The third part is the iterator, in which you update the value of the counter variable. All of this is enclosed in parentheses.

A simple for loop is shown in Example 6-13.

Example 6-13. A for loop
using System;
public class Tester
{

    public static void Main()
    {
        for (int counter=0; counter<10; counter++)
        {
            Console.WriteLine(
                "counter: {0} ", counter);
        }
    }
}
Output:
counter: 0
counter: 1
counter: 2
counter: 3
counter: 4
counter: 5
counter: 6
counter: 7
counter: 8
counter: 9

The counter variable is initialized to zero in the initializer:

for (int counter=0; counter<10; counter++)

The value of counter is tested in the expression part of the header:

for (int counter=0; counter<10; counter++)

Finally, the value of counter is incremented in the iterator part of the header:

for (int counter=0; counter<10; counter++)

The initialization part runs only once, when the for loop begins. The integer value counter is created and initialized to zero, and the test is then executed. Since counter is less than 10, the body of the for loop runs and the value is displayed.

After the loop completes, the iterator part of the header runs and counter is incremented. The value of the counter is tested, and, if the test evaluates true, the body of the for statement is executed again.

The logic of the for loop is as if you said, "For every value of counter that I initialize to zero, take this action if the test returns true, and after the action, update the value of counter."

6.3.4.1 Breaking out of a for loop

It is possible to exit from a for loop even before the test condition has been fulfilled. To end a for loop prematurely, use the unconditional branching statement break.

The break statement halts the for loop, and execution resumes after the for loop statement (or closing brace), as in Example 6-14.

Example 6-14. Using break to exit a for loop
using System;
public class Tester
{

    public static void Main()
    {
        for (int counter=0; counter<10; counter++)
        {
            Console.WriteLine(
                "counter: {0} ", counter);

          // if condition is met, break out.
            if (counter == 5)                   {
                Console.WriteLine("Breaking out of the loop");
                break;              
            }
        }

        Console.WriteLine("For loop ended");
    }
}
Output:
counter: 0
counter: 1
counter: 2
counter: 3
counter: 4
counter: 5
Breaking out of the loop
For loop ended

In this for loop you test whether the value counter is equal to 5. If that value is found (and in this case it always will be), you break out of the loop.

6.3.4.2 The continue statement

Rather than breaking out of a loop, you may at times want the semantics of saying "don't execute any more statements in this loop, but start the loop again from the top of the next iteration." To accomplish this, use the unconditional branching statement continue.

Break and continue create multiple exit points and make for hard-to-understand, and thus hard-to-maintain, code. Use them with some care.

Example 6-15 illustrates the mechanics of both continue and break. This code, suggested to me by one of my technical reviewers, Donald Xie, is intended to create a traffic signal processing system.

The signals are simulated by entering numerals and uppercase characters from the keyboard, using the Console.ReadLine() method, which reads a line of text from the keyboard. ReadLine() reads a line of text into a string variable. The string ends when you press the Enter key.

The algorithm is simple: receipt of a "0" (zero) means normal conditions, and no further action is required except to log the event. (In this case, the program simply writes a message to the console; a real application might enter a time-stamped record in a database.)

An algorithm is a well-defined series of steps to accomplish a task.

On receipt of an Abort signal (simulated with an uppercase "A"), the problem is logged and the process is ended. Finally, for any other event, an alarm is raised, perhaps notifying the police. (Note that this sample does not actually notify the police, though it does print out a harrowing message to the console.) If the signal is "X," the alarm is raised but the while loop is also terminated.

Example 6-15. Break and continue
using System;
public class Tester
{
    public static int Main()
    {
        string signal = "0";      // initialize to neutral
        while (signal != "X")      // X indicates stop
        {
            Console.Write("Enter a signal. X = stop. A = Abort: ");
            signal = Console.ReadLine();

            // do some work here, no matter what signal you 
            // receive 
            Console.WriteLine("Received: {0}", signal);

            if (signal == "A")
            {
                // faulty - abort signal processing
                // Log the problem and abort.
                Console.WriteLine("Fault! Abort\n");
                break; 
            }
 
            if (signal == "0")
            {
                // normal traffic condition
                // log and continue on
                Console.WriteLine("All is well.\n");
                continue; 
            }
 
            // Problem. Take action and then log the problem
            // and then continue on
            Console.WriteLine("{0} -- raise alarm!\n", 
                signal);
        }
        return 0;
    }
}

 Output 1:
Enter a signal. X = stop. A = Abort: 0
Received: 0
All is well.
Enter a signal. X = stop. A = Abort: 1
Received: 1
1 -- raise alarm!
Enter a signal. X = stop. A = Abort: X
Received: X
X -- raise alarm!
Press any key to continue...
 Output 2:
Enter a signal. X = stop. A = Abort: A
Received: A
Fault! Abort
Press any key to continue...

The point of this exercise is that when the A signal is received, the action in the if statement is taken and then the program breaks out of the loop, without raising the alarm. When the signal is 0 it is also undesirable to raise the alarm, so the program continues from the top of the loop.

Be sure to use uppercase letters for X and A. To keep the code simple there is no code to check for lowercase letters or other inappropriate input.

6.3.4.3 Optional for loop header elements

You will remember that the for loop header has three parts — initialization, expression, and iteration — and the syntax is as follows:

for ([initializers]; [expression]; [iterators]) statement

Each part of the for loop header is optional. You can, for example, initialize the value outside the for loop, as shown in Example 6-16.

Example 6-16. No initialization with for loop
using System;
public class Tester
{

    public static void Main()
    {
        int counter = 0;
        // some work here
        counter = 3;
        // more work here

        for ( ; counter<10; counter++)
        {
            Console.WriteLine(
                "counter: {0} ", counter);
        }
    }
}
Output:
counter: 3
counter: 4
counter: 5
counter: 6
counter: 7
counter: 8
counter: 9

In this example, the counter variable was initialized and modified before the for loop began. Notice that a semicolon is used to hold the place of the missing initialization statement.

You can also leave out the iteration step if you have reason to increment the counter variable inside the loop, as shown in Example 6-17.

Example 6-17. Leaving out the iterator step
using System;
public class Tester
{

    public static void Main()
    {

        for (int counter = 0; counter<10; ) // no increment
        {
            Console.WriteLine(
                "counter: {0} ", counter);

            // do more work here

            counter++; // increment counter
        }
    }
}

You can mix and match which statements you leave out of a for loop. It is even possible to leave all the statements out, creating what is known as a forever loop:

for ( ;; )

You break out of a forever loop with a break statement. A forever loop is shown in Example 6-18.

Example 6-18. A forever loop
using System;
public class Tester
{
    public static void Main()
    {
        int counterVariable = 0;  // initialization

        for ( ;; )
        {
            Console.WriteLine(
                "counter: {0} ", counterVariable++); // increment

            if (counterVariable > 10) // test
                break;
        }
    }
}
Output:
counter: 0
counter: 1
counter: 2
counter: 3
counter: 4
counter: 5
counter: 6
counter: 7
counter: 8
counter: 9
counter: 10

Use a forever loop to indicate that the "normal" case is to continue the loop indefinitely. The conditions for breaking out of the loop would then be exceptional and managed inside the body of the loop.

While it is possible to use a forever loop to good effect, Example 6-18 is a degenerate case. The initialization, increment, and test would be done more cleanly in the header of the for loop, and the program would then be easier to understand. It is shown here to illustrate that a forever loop is possible.

6.3.4.4 The while (true) construct

You can accomplish exactly the same semantics of a forever loop using the while (true) construct, as shown in Example 6-19.

Example 6-19. The while (true) construct
using System;
public class Tester
{
    public static void Main()
    {
        int counterVariable = 0;  // initialization

        while (true) 
        {
            Console.WriteLine(
                "counter: {0} ", counterVariable++); // increment

            if (counterVariable > 10) // test
                break;
        }
    }
}
 Output:
counter: 0
counter: 1
counter: 2
counter: 3
counter: 4
counter: 5
counter: 6
counter: 7
counter: 8
counter: 9
counter: 10

Example 6-19 is identical to Example 6-18 except that the forever construct:

for ( ;; )

is replaced with a:

while (true)

statement. Of course, the keyword true always returns the Boolean value true; so like the forever loop, this while loop runs until the break statement is executed.

    Team LiB   Previous Section   Next Section