Section 3 - A Closer Look at For Loops

Let's dig a little deeper into the first type of loop, the for loop.

4A.3.1 For Loops - A Closer Look

You rent a house at $1700 per month.  You can expect the rent to increase, on average, 5% per year.  After five years, how much have you spent on rent?  The first year is easy:  $1700 * 12.  But for the second year we have to multiply 1700 by 1.05 to get the new rent, and the years after that require even more computation.  With loops this is very easy.

We use a variable called rent and multiply it by 1.05 each year to get the new year's rent.  We add as we go along.  Here is the loop.

rent = 1700;   // our initial rent
total = 0;     // keeps track of how much we paid "so far"

// loop for five years
for (year = 1; year <= 5; year = year + 1)
{
costThisYear = rent * 12;
total = total + costThisYear;

// now increase the rent in prep for the next year
rent = rent * 1.05;
}

Notice that there is no semicolon after the loop control.  If there had been it would be an error:

// loop for five years
for (year = 1; year <= 5; year = year + 1);
{
costThisYear = rent * 12;
total = total + costThisYear;
// etc ,,,

Look up.  You are looking at the number one error among beginning C++ programmers. The statement does compile and execute but the compiler thinks that the programmer doesn't want any statements in the loop body. The semicolon at the end of the loop control line is premature and tells the compiler that there is nothing in the loop body. Don't put a semicolon after the loop control unless you intentionally want an empty body (which may well be!).

Before going on, let's look at a smart version of the above loop in a full program. Here we use shortcuts like *= and ++ as well as using the alternate method of defining constants called the #define statement.  Study this for full comprehension, then you can read on:

#include <iostream>
using namespace std;

#define INITIAL_RENT 1700

int main()
{
double rent, total, costThisYear;
int year;

rent = INITIAL_RENT;	        // our initial rent
total = 0;                   // keeps track of how much we paid "so far"

// loop for five years
for (year = 1; year <= 5; year++)
{
costThisYear = rent * 12;
total += costThisYear;

// now increase the rent in prep for the next year
rent *= 1.05;
}

cout << "\nYou will have paid $" << total << " after five years\n\n";

return 0;
}

/* ----------------------- SAMPLE RUN ----------------------------

You will have paid $112723 after five years

Press any key to continue . . .
------------------------- END SAMPLE RUN ----------------------- */

That's a lot of rent to pay in five years:  $112,723!

The loop control is broken down into three sections, each separated by a semicolon:

for ( <initialization> ; <test> ; <iteration> )

The first section is an initialization, and the statement that you place here is executed only once prior to entering the loop. Virtually any C++ statement can go into this section.  In fact, you can include several statements here, all intended to be initializations.  If you do want to have multiple initialization statements in the first section, use commas -- not semicolons -- to separate them:

for (total = 0, year = 1, rent = INITIAL_RENT ; year <= 5; year++)

The second section is a test performed at the beginning of each loop iteration (or loop pass). If the test results in a true value, then the loop body is executed one more time. If it is false, the loop terminates and control passes to the statement following the loop body.

The third section is the iteration and contains any statement (or statements, again separated commas if more than one) that you want to execute at the end of each loop pass. In the above loop we wanted year to be iterated, so we had an appropriate assignment statement, year = year + 1, in the first code example, and the shorter, but equivalent, year++, in the second.

The body of the loop is the single statement following the control. If more than one statement is to be executed at each pass of the loop, they are placed

in braces:

for (k=0, sum=0;  k < 5; k=k+1)
{
// statement 1
// statement 2
// statement 3
}
// the next statement after the loop.

Nothing in a for loop is done automatically.

Notice how much we can put into the loop control if we wish. The following does everything the longer version, above, does, but it has more of the bookkeeping built-in to the loop control:

#include <iostream>
using namespace std;
#define INIT_RNT 1700

int main()
{
double rent, total;
int year;

// loop for five years
for (total = 0, year = 1, rent = INIT_RNT;   year <= 5;   year++, rent *= 1.05)
total += (rent * 12);
cout << "\nYou will have paid $" << total << " after five years\n\n";

return 0;

4A.3.2 Variations on the For Loop

If we wish, we may have a termination condition that has nothing to do with the number of loop passes:

#include <iostream>
using namespace std;

int main()
{
double withdrawal, balance;

for (balance = 1000;   balance > 0;  )
{
cout << "Amount of withdrawal: ";

// get the withdrawal and subtract from balance
cin >> withdrawal;
balance = balance - withdrawal;

cout << "New balance:" <<  balance << endl;
}

// loop ends when we are broke
cout <<
"Sorry, you're out of money.  ATM Card confiscated.\n\n";
}
/* ----------- Output ----------------

Amount of withdrawal: 250
New balance:750.0
Amount of withdrawal: 500
New balance:250.0
Amount of withdrawal: 332
New balance:-82.0
Sorry, you're out of money.  ATM Card confiscated.

------------------------------------- */

We see that the third section of the loop can be empty. Everything we need to do at the end of each loop is already done. We could even move the last statement of the loop body into the loop control:

for (balance = 1000;   balance > 0;
cout << "New balance:" <<  balance << endl)
{
cout << "Amount of withdrawal: ";

// get the withdrawal and subtract from balance
cin >> withdrawal;
balance = balance - withdrawal;
}

Because we now have a long loop control, I broke it up onto two lines indenting the continuation line.

Normally, if a statement is sufficiently close (semantically) to the others in the block, it should stay in the block. If it is conceptually separate and seems to be more of a bookkeeping statement than a data manipulation statement, it should go in the control.

Finally, let's consider the general math problem, AP, that is A raised to the P. Can you scribble on a paper the for loop needed to do this without looking below?  Assume that A and P are each int variables and have positive values in them.  How would you have the computer figure out the answer, AP, and store it into the variable result?  When you are ready, look at one solution:

result = 1;
for ( k = 0; k < P; k = k + 1 )
result = result * A;

In this loop I counted to P by having k go from 0 to P-1:

for (k = 0; k < P; k = k + 1 )

This is the usual way to count in C++. This is because arrays (when we get to them) begin from 0, not 1, so this type of counting is more useful.

Just for fun let's see how terse we can make this code. Remember, I said that a short hand way to write k = k + 1 is k++? You can also abbreviate k = k - 1 to k--. Add this notation to another short-cut and we get the loop:

result = 1;
for ( ; P > 0; P--)
result = result*A;

This loop can be condensed to be even more compact and unreadable. Can you do it?