Free Hosting

For statements


By far, the most utilized looping statement in C++ is the for statement. The for statement is ideal when we know exactly how many times we need to iterate, because it lets us easily declare, initialize, and change the value of loop variables after each iteration.
The for statement looks pretty simple:
for (init-statement; expr1; expr2)
   statement;
The easiest way to think about for loops is convert them into equivalent while loops. In older versions of C++, the above for loop was exactly equivalent to:
// older compilers
init-statement;
while (expr1)
{
    statement;
    expr2;
}
However, in newer compilers, variables declared during the init-statement are now considered to be scoped inside the while block rather than outside of it. This is known as loop scope. Variables with loop scope exist only within the loop, and are not accessible outside of it. Thus, in newer compilers, the above for loop is effectively equivalent to the following while statement:
// newer compilers
{
    init-statement;
    while (expr1)
    {
        statement;
        expr2;
    }
} // variables declared in init-statement go out of scope here
for statement is evaluated in 3 parts:
1) Init-statement is evaluated. Typically, the init-statement consists of variable declarations and assignments. This statement is only evaluated once, when the loop is first executed.
2) The expression expr1 is evaluated. If expr1 is false, the loop terminates immediately. If expr1 is true, the statement is executed.
3) After the statement is executed, the expression expr2 is evaluated. Typically, this expression consists of incremented/decrementing the variables declared in init-statement. After expr2 has been evaluated, the loop returns to step 2.
Let’s take a look at an example of a for loop:
1
2
for (int iii=0; iii < 10; iii++)
    cout << iii << " ";
What does this do? Although this looks somewhat confusing, let’s take it piece by piece.
First, we declare a loop variable named iii, and assign it the value 0.
Second, the iii < 10 is evaluated, and since iii is 0, 0 < 10 evaluates to true. Consequently, the statement executes, which prints 0.
Third, After the statement executes, iii++ is evaluated, which increments iii to 1. Then the loop goes back to the second step.
1 < 10 is evaluates to true, so the loop iterates again. The statement prints 1, and iii is incremented to 2. 2 < 10 evaluates to true, the statement prints 2, and iii is incremented to 3. And so on.
Eventually iii is incremented to 10, 10 < 10 evaluates to false, and the loop exits.
Consequently, this program prints the result:
0 1 2 3 4 5 6 7 8 9
For loops can be hard for new programmers to read -- however, experienced programmers love them because they are a very compact way to do loops of this nature. Let's uncompact the above for loop by converting it into it's while-statement equivalent:
1
2
3
4
5
6
7
8
{
    int iii = 0;
    while (iii < 10)
    {
        cout << iii << " ";
        iii++;
    }
}
That doesn't look so bad, does it? Note that the outer braces are necessary here, because iii goes out of scope when the loop ends (in newer compilers).
Here is an example of a for loop affecting a variable declared outside the for loop:
1
2
3
4
5
6
7
8
9
// returns the value nBase ^ nExp
int Exponent(int nBase, int nExp)
{
    int nValue = 1;
    for (int iii=0; iii < nExp; iii++)
        nValue *= nBase;
    return nValue;
}
This function returns the value nBase^nExp (nBase to the nExp power).
This is a straightforward incrementing for loop, with iii looping from 0 up to (but excluding) nExp.
If nExp is 0, the for loop will execute 0 times, and the function will return 1.
If nExp is 1, the for loop will execute 1 time, and the function will return 1 * nBase.
If nExp is 2, the for loop will execute 2 times, and the function will return 1 * nBase * nBase.
Although most for loops increment the loop variable by 1, we can decrement it as well:
1
2
for (int iii = 9; iii >= 0; iii--)
    cout << iii << " ";
This prints the result:
9 8 7 6 5 4 3 2 1 0
Alternately, we can change the value of our loop variable by more than 1 with each iteration:
1
2
for (int iii = 9; iii >= 0; iii -= 2)
    cout << iii << " ";
This prints the result:
9 7 5 3 1
Off-by-one errors
One of the biggest problems that new programmers have with for loops is off-by-one errors. Off-by-one errors occur when the loop iterates one too many or one too few times. This generally happens because the wrong relational operator is used in expr1 (eg. > instead of >=). These errors can be hard to track down because the compiler will not complain about them -- the program will run fine, but it will produce the wrong result.
When writing for loops, remember that the loop will execute as long as expr1 is true. Generally it is a good idea to test your loops using known values to make sure that they work as expected. If your loop produces the right result when it iterates 0, 1, and 2 times, it will probably work for all number of iterations.
Omitted expressions
It is possible to write for loops that omit any or all of the expressions. For example:
1
2
3
4
5
6
int iii=0;
for ( ; iii < 10; )
{
    cout << iii << " ";
    iii++;
}
This for loop produces the result:
0 1 2 3 4 5 6 7 8 9
Rather than having the for loop do the initialization and incrementing, we've done it manually. We have done so purely for academic purposes in this example, but there are cases where not declaring a loop variable (because you already have one) or incrementing it (because you're incrementing it some other way) are desired.
Although you do not see it very often, it is worth noting that the following example produces an infinite loop:
for (;;)
    statement;
The above example is equivalent to:
while (true)
    statement;
Null statements
It is also possible to omit the statement part of a for loop. This is called a null statement, and it is declared by using a single semicolon.
1
2
for (int iii=0; iii < 10; iii++)
    ;
This loop increments iii using the ++ operator 10 times. When the statement is executed, the null statement evaluates to nothing, and consequently, doesn't do anything. For readability purposes, the semicolon of a null statement is typically placed on it's own line. This indicates that the use of a null statment was intentional, and makes it harder to overlook the use of the null statement.
Null statements can actually be used anywhere a regular statement can (though they typically aren't, since they serve no purpose other than as a do-nothing placeholder). Because of this, it is easy to make the following mistake:
1
2
if (nValue == 0);
    nValue = 1;
The programmer's intent was to assign nValue the value of 1 only if nValue had the value 0. However, due to the misplaced semicolon after the if statement, this actually executes as:
1
2
3
if (nValue == 0)
    ;
nValue = 1;
Consequently, nValue is set to 1 regardless of it's previous value!
Multiple declarations
Although for loops typically iterate over only one variable, sometimes for loops need to work with multiple variables. When this happens, the programmer can make use of the comma operator in order to initialize or change the value of multiple variables:
1
2
for (int iii=0, jjj=9; iii < 10; iii++, jjj--)
    cout << iii << " " << jjj << endl;
This loop initializes two variable: iii to 0, and jjj to 9. It iterates iii over the range 0 to 9, and each iteration iii is incremented and jjj is decremented.
This program produces the result:
0 9
1 8
2 7
3 6
4 5
5 4
6 3
7 2
8 1
9 0
This is the only place in C++ where the comma operator typically gets used.
Conclusion
For loops are the most commonly used loop in the C++ language. Even though it's syntax is typically a bit confusing to new programmers, you will see for loops so often that you will understand them in no time at all!
Quiz
1) Write a for loop that prints every other number from 0 to 20.
2) Write a function named SumTo() that takes an integer parameter named nValue, and returns the sum of all the numbers from 1 to nValue.
For example, SumTo(5) should return 15, which is 1 + 2 + 3 + 4 + 5.
Hint: Use a non-loop variable to accumulate the sum as you iterate from 1 to nValue, much like the Exponent() example above uses nValue to accumulate the return value each iteration.
3) What's wrong with the following for loop?
1
2
3
// Print all numbers from 9 to 0
for (unsigned int nCount = 9; nCount >= 0; nCount--)
    cout << nCount << " ";

0 comments:

Blogger Template by Clairvo