As we have seen in many previous examples involving iteration, the three key components of a loop are as follows:
Loop condition When evaluated to true, will cause the loop body to be repeated.
Loop initialization During the loop initialization the variable(s) taking part in the loop condition are assigned initial suitable values. This process only takes place once before the loop commences.
Loop update Updates the variables of the loop condition. This is repeatedly done during every loop.
These are exemplified in Figure 9.6, which uses the source code of the while loop shown earlier. Notice that only the loop condition is restrained by the rules of syntax to a specific position, namely inside a pair of parentheses positioned right after the while keyword. On the other hand, the loop initialization and loop update can be positioned anywhere. This is fine for a simple loop with a small loop body, such as the one shown here, but if initializations and updates are scattered around large amounts of code, it can become difficult to locate and remain conscious about these loop hotspots. All too often, this results in while or do-while loops that, during alterations, only have one or two key components modified without the necessary adjustments for the third components.
The for loop addresses this potential problem by providing exact syntactic rules for the location of all three loop control elements. As Syntax Box 9.3 shows, all three elements must be enclosed in parentheses next to the for keyword and separated by semicolon.
Syntax Box 9.3 The for-Loop Statementfor ( [<Initialization_statements>] ; [<Loop_condition>] ; [<Update_statements>] ) <Loop_body> where: <Loop_body>::= <statement>; ::= <Compound_statement> <Initialization_statements>::= <Initialization_statement1>, <Initialization_statement2>... <Loop_condition>::= <Boolean_expression> <Update_statements>::= <Update_statement1>, <Update_statement2>... Note:
|
The syntax of the for loop allows us to implement the same semantics as the code of Figure 9.6. This is done in Figure 9.7. It is important to notice that the timing of events taking place in the for loop are the same as those of the displayed while loop, which means
The loop initialization takes place only once on entry to the loop.
The loop condition is evaluated at the beginning of each iteration.
The loop update is performed at the end of each iteration.
Note
The for and while loop constructs are both entry condition loops. The do-while loop is the only exit condition loop in C#. |
Note
The loop body of the for statement can, like that of the while and do-while loops, be either a single or compound statement. The three different loop constructs are always counted as a single statement, disregarding the number of statements it contains in the loop body. |
The following discusses the implications of the notes written in Syntax Box 9.3.
1. Each of the three loop parts in the for loop is optional, however the parentheses after the for keyword must always contain three semicolons.
Example: Figure 9.7 showed us how a while loop can be converted to fit into the conventional framework of a for loop. Conversely, Figure 9.8 illustrates how the for loop can mimic the syntax of the while loop, the only difference being the for keyword and a couple of semicolons. The loop initialization index = 0 of the for loop has been removed from its position inside the parentheses to line 2, and the loop update index++ removed to line 6.
It is even possible to omit the loop condition and leave the parentheses empty apart from the obligatory semicolons. A missing loop condition is interpreted by the compiler to be a loop condition that is always true, making for( ; ; ) equivalent to for( ; true; ). The following would thus constitute an infinite loop:
for ( ; ; ) { Console.WriteLine("I'm repeated infinitely many times"); }
Notice that the following while and do-while statements also constitute infinite loops:
while(true) { Console.WriteLine("Pyyyhhhh, this is hard work"); } do { Console.WriteLine("As spoken out of my mouth"); } while (true)
You might, with good reason, wonder if a loop condition that is always true has any practical use. It turns out that it can be used together with the break statement you already met during the switch statement discussion, but more about this later in the section "The Jump Statements break and continue".
2. The loop initialization and loop update can consist of several statements separated by commas, but only a maximum of one loop condition is permitted.
Because of this, it is possible to include as many initializations and updates as you want within the parentheses after the for keyword.
The program in Listing 9.4 utilizes this feature to determine a number positioned between the initial values of i and j (in this case 0 and 21) for which it is true that it is one third from i towards j (and two thirds from j towards i). The loop body of the for loop prints the values of i and j as they get closer to the solution. In this case, the answer is 7, as shown in the final line of the sample output.
01: using System; 02: 03: class OneThird 04: { 05: public static void Main() 06: { 07: int i; 08: int j; 09: 10: Console.WriteLine("Value of\n i j\n"); 11: for (i=0, j=21; i <= j; i++, j=j-2) 12: Console.WriteLine(" {0} {1} ", i, j); 15: } 16: } Value of i j 0 21 1 19 2 17 3 15 4 13 5 11 6 9 7 7
Line 11 specifies the for loop to enclose two initialization statements (i = 0 , j = 21) and two update statements (i++ , j = j - 2), in each case separated by the comma operator (see the following Note), whereas the loop body of line 12 merely performs a simple printout. Because j is decremented by 2 every time i is incremented by 1, i will be greater than j, and will make the loop condition i <= j false, approximately when i is one third toward the original value of j and j is two thirds towards the original value of i.
The Comma Operator
The language element allowing us to squeeze two or more expressions into the space of one for statement is called the comma operator. The effect of the comma operator, as in the following for (i=0, j=21; i <= j; i++, j=j-2) //combining i=0, j=21 and //combining i++ and j=j-2 is to combine two or more statements to count as one and, hence, fit where just one statement is expected. The comma operator should not be confused with:
|
Note
You can only have a maximum of one loop condition in the for statement, but because the loop condition is a Boolean expression, you can still use the logical operators (&&, ||, !, &, |, ^) to form longer Boolean expressions. |
Tip
Only use the loop initialization and loop update for variables that are part of the loop condition. The comma operator allows you to insert an infinite number of expressions into the space of the loop initializations and loop updates. It can be tempting to cram initializations and updates in here other than those directly linked to the variable(s) of the loop condition. Listing 9.5 illustrates this. It creates a table of heights and widths and, for each pair, calculates the resulting area. |
01: using System; 02: 03: class AreaCalculator 04: { 05: public static void Main() 06: { 07: int i; 08: int width; 09: int height; 10: 11: Console.WriteLine("height width area\n"); 12: for (height = 1000, width = 100, i=0; i <= 10; 13: height = height + 100, width = width + 10, i++) 14: { 15: Console.WriteLine("{0} {1} {2} ", 16: height, width, height * width); 17: } 18: } 19: } height width area 1000 100 100000 1100 110 121000 1200 120 144000 1300 130 169000 1400 140 196000 1500 150 225000 1600 160 256000 1700 170 289000 1800 180 324000 1900 190 361000 2000 200 400000
Note that lines 12 and 13 not only contain the loop initialization and loop updates for the loop condition variable i, they also contain initializations and updates for width and height. Consequently, the only thing left for the loop body to do is to print out the values calculated in the loop initialization and updates. Notice that it becomes hard to distinguish between the elements dealing with the control of the loop (the variable i) and those that are merely part of the processes performed during each loop. The ability and advantage of the for statement to enable a separation between the loop controlling parts and other processes performed during one loop has been misused, resulting in cluttered, unclear, ugly code. Listing 9.6 shows an improved version with exactly the same functionality as Listing 9.5.
01: using System; 02: 03: class AreaCalculator 04: { 05: public static void Main() 06: { 07: int i; 08: int width; 09: int height; 10: 11: height = 1000; 12: width = 100; 13: Console.WriteLine("height width area\n"); 14: for (i=0; i <= 10; i++) 15: { 16: Console.WriteLine("{0} {1} {2}", 17: height, width, height * width); 18: height = height + 100; 19: width = width + 10; 20: } 21: } 22: }
The output is the same as that from Listing 9.5.
The initializations and updates of height and width have been removed from the pair of parentheses following the for keyword. The initializations have been put in lines 11 and 12 prior to the for statement, and the updates have become part of the loop body where they belong.
The simple appearance of line 14 of this listing, compared to that of lines 12 and 13 in Listing 9.5, allows the reader to easily grasp the essential workings of this for loop.
i and j As Names for Counting Variables
The use of i and j as names for counting variables has a long (in terms of computing history) history behind it. The tradition was established with the FORTRAN language in that it only allowed variables with the names i, j, k, l, m, and n to be used for counting purposes. The impact of this tradition is widespread throughout the programming community where you will often encounter those names used for counting variables. |