Counting Loops

download the slides used in this presentation
PowerPoint pptx | Acrobat pdf

Objectives

While engaging with this module, you will...

  1. further your looping capabilities by using the for-loop
  2. extend your understanding of C++ branching with the concept of scoping

The for Loop

The syntax for the for statement is:

for (expression1; expression2; expression 3)
    statement

The details:

Note:   This is a counting loop. Many people will monkey with the format to turn it into a sentinel loop. That is bad form; if you need a sentinel loop, use while or do-while statements.

For example, prompt for and read in a positive integer and output the average of the positive integers less than or equal to this value.

float average;
long sum = 0;
short i = 0;

cout<<”enter positive integer: “;
cin>>max;

for(i=0; i <= max; i++)
    sum += i;                             // sums integers up to max

average = static_cast<float>(sum) / max;  //cast because integer division!
cout<<"average is "<<average<<endl;

There are several considerations to look at here. Why did I initialize sum, but not average? Average will be assigned a value to output; there is no necessity to initialize. On the other hand, if I did not initialize sum, I won’t know what the sum starts out as when I start accumulating that sum. It could possibly (likely) give me false results! Did I have to initialize i? No. It will be initialized inside the for statement. Why did I use the identifier ‘i’? Isn’t that a “bad” name for a variable? Yes, normally you want to pick names for variables that mean something to the reader of the program. However, this variable is a counter. It is very common to use i, j, k and even sometimes n for indices like this. Why was the sum cast as a float? If I didn’t do the cast, then the result would have no fractional part – it would be chopped to an integer result. Keep in mind that this code required a loop for which I knew a priori how many iterations of the computation were required. A counting loop was most appropriate. I could have used a sentinel loop, creating a counter (the sentinel) to terminate the loop, but the for wraps this up for you in one convenient statement.

For example, modify the previous example: average only the even integers...

for(i=0; i <= max; i+=2)
    sum += i;                             // sums integers up to max

average = static_cast<float>(sum) / max;  //cast because integer division!

The only difference here is that I’ve changed the update part of the for loop. Some would be tempted to do this with an if statement inside the loop body. This would be inefficient.

As another example, produce the pattern of stars pictured here:

* * * * *
* * * *
* * *
* *
*

If we analyze the requirement of the output, we can see that we will need two loops, one inside the other. The “outer” loop will control the number of lines of output, and the “inner” loop will control the number of *’s printed per line. Also, we will need an endl at the end of each line. Thus, we have

for( int i=1; i <= 5; i++ )  // lines
{
    for(int j= ??? )
        cout<<"* ";          // a star and a space

    cout<<endl;
}

So, for the outer loop, we run our LCV (an index) from 1 to 5 since we have 5 lines of output. What do we need for the inner for loop? Notice that the number of *’s is dependent on the line we’re on. That is, the number of stars on any given line is a function of the line number. For line 1, we want 5 stars; line 2, 4 stars; etc.

for( int i=1; i <= 5; i++ ) // lines
{
    for( int j=1; j <= 5 – i + 1; j++ )  // stars per line
        cout<<"* ";                      // a star and a space

    cout<<endl;
}

Ok, we have for line #4, for( int j=1; j <= 2; j++), which will produce 2 stars. I think we have it.

For example, produce the pattern of stars pictured here:

* * * * *
  * * * *    note: The dimension of this pattern could be read in as a
    * * *    parameter from the user. I’ll do dim = 5 here.
      * *
        *

This one is a bit more difficult.

for (short i = 0; i < 5; i++)
{
    for (short j = 1; j <= i; j++)
        cout<<" ";                  // two spaces

    for (short j = i; j < 5; j++)
        cout<<"* ";                 // star and space

    cout<<endl;
}

As you see, it requires a nested loop to get the job done. The first (outside) loop controls the number of lines in the pattern and the two inside loops control the number of spaces and stars, respectively. Notice that the output of the endl is not in either of the inside loops.

Scope:

for ( int i=1; i <= 10; i++ )
    cout<<"hello"<<endl;

cout<<i<<endl;

Here we have declared and initialized the index for the loop inside the loop. It would appear that this code should compile and run fine. But it doesn’t. Why? The compiler will give you a "undeclared identifier" error for the second cout statement; i doesn’t exist in this scope.

Scope determines the lifetime of a variable. A block of code will determine scope. In the above example, the block of code that determines i’s scope, and its lifetime, is the for statement. i was declared inside the loop, so it only exists in that loop. Get outside that loop (the for statement) and it no longer exists. Let’s modify the example:

int i=20;

for ( i=1; i <= 10; i++ )
    cout<<"hello"<<endl;

cout<<i<<endl;

Now the second cout statement compiles just fine and results in output of 11. (Why?) The scope of i is the whole block of code above and any code after the point of declaration of that variable. What is the output? It will be 11. Remember, the scope includes that loop and i has changed in the loop.

Let’s change the example again.

int i=20;

for(int i=1; i<=10; i++)
    cout<<"hello"<<endl;

cout<<i<<endl;

Do you think it will compile? Raise your hand if you think it will compile. (If you raised your hand, you can put it down tomorrow at noon.) The answer is yes, it will compile. So what’s going on here?? The i that is declared in the loop is said to “hide” the i that was declared in the outer block (the for statement is the inner block). Do you know what the output is? What i is referred to in that cout statement? 20 is the output, not 11. As soon as the for statement is finished, the i declared there goes out of scope and the outer i is unhidden.

A good programmer should avoid such situations – it only leads to confusion and heartbreak.

Course Menu
0. Getting Started
0.0. Welcome
1. The Big Picture
2. Programming Fundamentals
3. Operators
4. Branching
5. Loops
6. Advanced Branching
7. Odds and Ends
8. Functions
9. Random Number Generation
10. Multiple Files
11. Arrays
12. Structs
13. Character Arrays
14. File I/O
15. Objects
16. Output Formatting
16.0. Overview
17. Namespaces
18. Enumerations
19. Sample Homework