Team LiB
Previous Section Next Section

Loops and Other Flow of Control Structures

Very rarely will a program execute sequentially, line-by-line from start to finish. Instead, the execution flow of the program will be conditional. It may be necessary to have the program execute a certain block of code if a condition is met, or another block of code if the condition isn't met. A program may have to repeatedly execute the same block of code. The C# language provides a number of different types of loops and other flow of control structures to take care of these situations.

if Statements

The if statement is a basic conditional branch statement that executes one or more lines of code if a condition, represented as a logical expression, is satisfied. Alternatively, one or more lines of code can be executed if the condition is not satisfied by placing that code after the keyword else. The use of an else clause with an if statement is optional.

The basic syntax of the if statement is as follows:

if (condition) {
  execute whatever code is contained within the braces if condition is met
}

or, adding an optional else clause:

if (condition) {
  execute whatever code is contained within the braces if condition is met
}
else {
  execute whatever code is contained within the braces if condition is NOT met
}

If only one executable statement follows either the if or (optional) else keyword, the braces can be omitted as shown here:

// Pseudocode.
if (condition) single statement to execute if true;
else single statement to execute if false;

but it's generally considered good practice to always use braces.

A single Boolean variable, as a simple form of Boolean expression, can of course serve as the logical expression/condition of an if statement. For example, it's perfectly acceptable to write the following:

// Use this bool variable as a 'flag' that gets set to true when
// some particular operation is completed.
bool finished;

// Initialize it to false.
finished = false;

// Intervening code, in which the flag may get set to true ... details omitted.

// Test the flag.
if (finished) { // equivalent to: if (finished == true) {
    Console.WriteLine("we are finished");
}

In this case the logical expression serving as the condition for the if statement corresponds to "if finished" or, alternatively, "if finished equals true".

The ! operator can be used to negate a logical expression, so that the block of code associated with an if statement is executed when the expression is false.

if (!finished) { // equivalent to: if (finished == false)
    // If the finished variable is set to false, this code will execute.
    Console.WriteLine("we are not finished");
}

In this case, the logical expression serving as the condition for the if statement corresponds to "if not finished" or, alternatively, "if finished equals false".

When testing for equality, remember that we must use two consecutive equal signs, not just one:

if (x == 3) { // Note use of double equal signs (==) to test for equality.
  y = x;
}
Note?/td>

A common mistake made by beginning C# programmers is to try to use a single equal sign to test for equality as in this example:

  if (x = 3) { ... }

In C#, an if test must be based on a valid logical expression; x = 3 isn't a logical expression, but rather, an assignment expression.

The preceding if statement won't even compile in C#, whereas it would compile in the C and C++ programming languages, because in those languages, if tests are based on evaluating expressions to either the integer value 0 (equivalent to false) or nonzero (equivalent to true).

It's possible to nest if-else constructs to test more than one condition. If nested, an inner if (plus optional else) statement is placed within the else part of an outer if.

A basic syntax for a two-level nested if-else construct is shown here:

if (condition1) {
  // execute this code
}
else {
  if (condition2) {
    // execute this alternate code
  }
  else {
    // execute this code if none of the conditions are met
  }
}

There is no limit (within reason!) to how many nested if-else constructs can be used.

The nested if statement shown in the preceding example may alternatively be written without using nesting as follows:

if (condition1) {
  // execute this code
}
else if (condition2) {
    // execute this alternate code
}
else {
    // execute this code if none of the conditions are met
}

The two forms are logically equivalent.

Here is an example that uses a nested if-else construct to determine the size of an employee's bonus based on the employee's sales and length of service:

using System;

public class IfDemo
{
  static void Main() {
    double sales = 40000.0;
    int lengthOfService = 12;
    double bonus;

    if (sales > 30000.0 && lengthOfService >= 10) {
      bonus = 2000.0;
    }
    else {
      if (sales > 20000.0) {
        bonus = 1000.0;
      }
      else {
        bonus = 0.0;
      }
    }

    Console.WriteLine("Bonus = " + bonus);
  }
}

Here's the output generated by this example code:

Bonus = 2000.0

switch Statements

A switch statement is similar to an if-else construct in that it allows the conditional execution of one or more lines of code. However, instead of evaluating a logical expression as an if-else construct does, a switch statement compares the value of an integer or string expression against values defined by one or more case labels. If a match is found, the code following the matching case label is executed. An optional default label can be included to define code that is to be executed if the integer or string expression matches none of the case labels.

The general syntax of a switch statement is as follows:

switch (int-or-string-expression) {
    case value1:
      // code to execute if expression matches value1
      break;
    case value2:
      // code to execute if expression matches value2
      break;
      // more case labels, as needed ...
      case valueN:
      // code to execute if expression matches valueN
      break;
    default:
      // default code if no case matches
    break;
}

For example:

int x;

// x is assigned a value somewhere along the line ... details omitted.

switch (x) {
    case 1:
      // Pseudocode.
      do something based on the fact that x equals 1
      break;
    case 2:
      // Pseudocode.
      do something based on the fact that x equals 2
      break;
    default:
      // Pseudocode.
      do something based on the fact that x equals something other than 1 or 2
      break;
}

Note the following:

  • The expression in parentheses following the switch keyword must be an expression that evaluates to a string or integer value. (Note that the char,

  • int, and long types are all considered to be forms of integer, and so any of these types of expression can be used.)

  • The values following the case labels must be constant values (a "hardwired" integer constant, character literal, or a string literal).

  • Colons, not semicolons, terminate the case and default labels.

  • The statements following a given case label don't have to be enclosed in braces. They constitute a statement list rather than a code block.

Unlike an if statement, a switch statement isn't automatically terminated when a match is found and the code following the matching case label is executed. To exit a switch statement, a jump statement must be used—typically, a break statement. If a jump statement isn't included following a given case label, the execution will "fall through" to the next case or default label. This behavior can be used to our advantage: when the same logic is to be executed for more than one case label, two or more case labels can be stacked up back to back as shown here:

// x is assumed to have been previously declared as an int
switch (x) {
    case 1:
    case 2:
    case 3:
        // code to be executed if x equals 1, 2, or 3
        break;
    case 4:
        // code to be executed if x equals 4
}

A switch statement is useful for making a selection between a series of mutually exclusive choices. In the following example, a switch statement is used to assign a value to a variable named capital based on the value of a variable named country. If a match isn't found, the capital variable is assigned the value "not in the database".

using System;

public class SwitchDemo
{
  static void Main() {

    string country;
    string capital;
    country = "India";

    // A switch statement compares the value of the variable "country"
    // against the value of three case labels. If no match is found,
    // the code after the default label is executed.

    switch (country) {
      case "England":
        capital = "London";
        break;
      case "India":
        capital = "New Delhi";
        break;
      case "USA":
        capital = "Washington";
        break;
      default:
        capital = "not in the database";
        break;
    }

    Console.WriteLine("The capital of " + country + " is " + capital);
  }
}

Here's the output for the preceding code example:

The capital of India is New Delhi

for Statements

A for statement is a programming construct that is used to execute one or more statements a certain number of times. The general syntax of the for statement is as follows:

for (initializer; condition; iterator) {
  // code to execute while condition is true
}

A for statement defines three elements that are separated by semicolons and placed in parentheses after the for keyword.

The initializer is used to provide an initial value for a loop control variable. The variable can be declared as part of the initializer or it can be declared earlier in the code, ahead of the for statement. For example:

  // The loop control variable 'i' is declared within the for statement:
    for (int i = 0; condition; iterator) {
      // code to execute while condition is true
  }
  // Note that i goes out of scope when the 'for' loop exits.

or:

  // The loop control variable 'i' is declared earlier in the program:
  int i;

  for (i = 0;condition; iterator) {
      // code to execute while condition is true
  }
  // Note that because i is declared before the for loop begins in this case,
  // i remains in scope when the 'for' loop exits.

The condition is a logical expression that typically involves the loop control variable:

  for (int i = 0; i < 5; iterator) {
      // code to execute as long as i is less than 5
  }

The iterator typically increments or decrements the loop control variable:

  for (int i = 0; i < 5; i++) {
      // code to execute as long as i is less than 5
  }

Again, note the use of a semicolon (;) after the initializer and condition, but not after the iterator.

Here's a breakdown of how a for loop operates:

  • When program execution reaches a for statement, the initializer is executed first (and only once).

  • The condition is then evaluated. If the condition evaluates to true, the block of code following the parentheses is executed.

  • After the block of code finishes, the iterator is executed.

  • The condition is then reevaluated. If the condition is still true, the block of code and update statement are executed again.

This process repeats until the condition becomes false, at which point the for loop exits.

Here is a simple example of using nested for statements to generate a simple multiplication table. The loop control variables, j and k, are declared inside their respective for statements. As long as the conditions in the respective for statements are met, the block of code following the for statement is executed. The ++ operator is used to increment the values of j and k each time the respective block of code is executed.

using System;

public class ForDemo
{
  static void Main() {
    // Compute a simple multiplication table.

    for (int j = 1; j <= 4; j++) {
      for (int k = 1; k <= 4; k++) {
        Console.WriteLine("" + j + " * " + k + " = " + (j * k));
      }
    }
  }
}

Here's the output:

1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
1 * 4 = 4
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
2 * 4 = 8

etc.

Note?/td>

Note the use of the string concatenation operator, +, in the ForDemo example; string representations of the value of int variables j and k are concatenated to the string literals "", " * ", and " = ".

Each of the three elements inside the parentheses of a for statement is optional (although the two separating semicolons are mandatory):

If the initializer is omitted, the loop control variable must have been declared and initialized before the for statement is encountered.

   int i = 0;
  for (; i < 5; i++) {

      // do some stuff as long as i is less than 5
  }

If the iterator is omitted, we must make sure to take care of explicitly updating the loop control variable within the body of the for loop to avoid an infinite loop:

  for (int i = 0; i < 5; ) {
      // do some stuff as long as i is less than 5

    // Explicitly increment i.
    i++;
  }

If the condition is omitted, the result is a potentially infinite loop:

  for (;;) {
       // infinite loop!
  }
Note?/td>

In the section titled "Jump Statements" later in this chapter, we'll see that jump statements can be used to break out of a loop.

As with other flow of control structures, if only one statement is specified after the for condition, the braces can be omitted:

for (int i = 0; i < 3; i++) sum = sum + i;

but it is considered good programming practice to use braces regardless.

while Statements

A while statement is similar in function to a for statement, in that both are used to repeatedly execute an associated block of code. However, if the number of times that the code is to be executed is unknown when the loop first begins, a while statement is the preferred choice, because a while statement continues to execute as long as a specified condition is met.

The general syntax for the while statement is as follows:

while (condition) {
  // code to execute while condition is true
}

The condition can be either a simple or complex logical expression that evaluates to a true or false value. For example:

int x = 1;
int y = 1;

while (x < 20 || y < 10) {
  // Pseudocode.
  presumably do something that affects the value of either x or y
}

When program execution reaches a while statement, the condition is evaluated first. If true, the block of code following the condition is executed. When the block of code is finished, the condition is evaluated again and if it's still true, the process repeats itself until the condition evaluates to false, at which point the while loop exits.

Here is a simple example illustrating the use of a while loop. A bool variable named finished is initially set to false. The finished variable is used as a flag: as long as finished is false, the block of code following the while loop will continue to execute. Presumably, there will be some condition inside the block of code that will eventually set finished to true, at which point the while loop will exit.

using System;

public class WhileDemo
{
  static void Main() {
    bool finished = false;
    int i = 0;

    while (!finished) {
      Console.WriteLine(i);
      i++;
      if (i == 3) finished = true; // toggle the flag value
    }
  }
}

Here's the output:

0
1
2

As with the other flow of control structures, if only one statement is specified after the condition, the braces can be omitted:

while (x < 20) x = x * 2;

but it is considered good programming practice to use braces regardless.

do Statements

With a while loop, the condition is evaluated before the code block following it is (conditionally) executed. Thus, it's possible that the code will never be run if the condition is false from the start. A do loop is similar to a while loop, except that the block of code is executed before the condition is evaluated. Therefore, we are guaranteed that the code block of the loop will be executed at least once.

The general syntax of a do statement is as follows:

do {
  // code to execute
} while (condition);

As was the case with the while statement, the condition of a do statement is a logical expression that evaluates to a Boolean value. A semicolon is placed after the parentheses surrounding the condition, to signal the end of the do statement. We typically use a do loop when we know that we need to perform at least one iteration of a loop for initialization purposes.

bool flag;

do {
  // perform some code regardless of initial setting of 'flag', then
  // evaluate whether the loop should iterate again based on the
  // value of 'flag'. The value of 'flag' can be set to false within
  // the loop to signal that the loop is to terminate.
} while (flag);

Team LiB
Previous Section Next Section