Section 9g

The C for Loop


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A Lot Like the while Loop

There are two basic kinds of loops in C, the pre-test loop and the post-test loop. The pre-test loop comes in two flavors, the one that uses the while statement, and the one that packages the while process in one for loop statement. In this topic, you will look at the for loop, and discover the differences, even though there aren't many.

Using the for Loop

The second form of the while loop is called the for loop, and it is easy to call this loop a "while loop in a can". This is because it is nothing more than a packaged version of the while loop. As long as there are while loops, you really do not need for loops. However, for some simple "counting" processes, such as the space printing process, it can be more convenient than the while loop.

The general form of the for loop is shown here.

for( < initialization process >;
< test for continuation process >;
< update process > )

You have to keep careful track of which action happens next in the for loop. The process order works as follows.

It is important to note that if you are going to use a for loop, you must fill in all three parts. The first problem is that if you are not using the three parts, you apparently don't need a for loop. But the second problem is bigger. If someone is reading your code and has to go searching elsewhere in your code to find the parts that should have been in the for statement, you are costing the company money (and frustrating the code reviewer).

The for loop for the space printing program would appear as follows.

// in global constant area of program
private final char SPACE = ' ';

// in function where loop is used (local)
int numberOfSpaces = 5;
int spaceCounter;

// iterate across number of spaces
for( spaceCounter = numberOfSpaces; spaceCounter > 0; spaceCounter-- )
{
// display space
// function: printChar
printChar( SPACE );
}
// end loop

The for loop algorithm is the same as the while loop algorithm shown previously. You can think of a for loop as a "packaged while loop" (i.e., "a while loop in a can" as stated previously). All the necessary ingredients are in one package. The initialization of the variable(s) or counter(s), which may be your loop control variable or action, is the first part: spaceCounter = numberOfSpaces.

The test required to continue the loop is the second part: spaceCounter > 0; remember this happens before the first iteration as well as before every other iteration (just like the while loop). Finally the update of appropriate variables, including the loop control variable or condition when appropriate, is the third part: spaceCounter--. Take a moment to compare this to the while loop form of this process.

Note that an extra variable (i.e., spaceCounter) has been used. This is sometimes required in a loop if there is a reason not to change the incoming data value (i.e., numberOfSpaces). It was not done in the while loop example, but it could just as easily have been.

Next, the letter counting loop can be evaluated as a for loop. The change making loop will be left as an exercise. The letter counting loop is probably best suited for a while loop because it tends to be more readable in the flow of the code. However, using it as an example of the for loop will help you again see how the loop puts all the processing in one place.

Shown next is the looping condition.

// in global constant area of program
private final char PERIOD = '.';

// in function where loop is (local)
int charCounter;
char testLetter;

// prompt the user for the characters
// function: printString
printString( "Enter a sentence ending with a period" );

// acquire the first character (prime)
// function: getChar
testLetter = getChar();

// loop until period found
for( charCounter = 0; testLetter != PERIOD; charCounter++ )
{
// get new character
// function: getChar
testLetter = getChar();;
}
// end loop

Now the above would be a normal way to use a for loop but it doesn't actually completely use the capability of a for loop. Remember that the first of the three for loop sections is for function initialization, and the last is for function update. Consider the following.

// in global constant area
const char PERIOD = '.';

// in function where loop is (local
int charCounter;
char testLetter;

// get the first character (prime the loop)
// function: printString
printString( "Enter a sentence ending with a period: " );

// loop until period found
// function: printString, getChar
for( charCounter = 0, testLetter = getChar();
testLetter != PERIOD;
charCounter++, testLetter = getChar() )
{
// nothing to do here
}
// end loop

This example is provided for two (almost three) reasons. First, you can do anything that is necessary for loop initialization in the first of the three sections of a for loop, and along with that, note that if you do more than one thing in either the initialization or update areas, you simply delimit or divide them with a comma. You cannot do that in the center part which must be one complete and correct logical statement.

The second reason for showing this is to demonstrate how perfectly good code can be written in a way that makes it hard to read and understand. You are always better off not to do this. There will be times that you need to initialize more than one thing, or update more than one thing in a for loop, and as long as the code remains completely readable, use the comma between the items and move on. However, any time you see code getting hard to read, stop what you are doing, back up, and find a way to make it better.

The loop algorithm is the same as the while loop algorithm shown previously. Once again, the charCounter is initialized, the condition to continue (i.e., testLetter != PERIOD) is tested prior to each iteration, and the charCounter is incremented after each iteration. As mentioned, this condition is probably better served with a while loop; however you can learn from this example how the for loop actually works.

Consider the following process of stepping through the loop. Each step of the code will be evaluated.

Now, given this thorough explanation of the process, can you see why the charCounter was initialized to zero, even though one character had already been input? Look at the process closely. The first character captured is assumed not to be a period.

However, even if it was, the process would be implemented as follows:

In the case where there were no letters and the first character was a period, the results are, charCounter would show a zero, which is correct. If the first character was a period, then there were no letters in the sentence.

Now consider a sentence with one letter. For the exercise, say that the sentence was "Z." (i.e., the letter 'Z' and a period) follow the steps shown.

Watch this video to see this operation tested.

The results now are that charCounter shows a one which again is correct. This for loop will work fine. Once again, this is an exaggerated condition to show the process. However, you can see pretty quickly that unless your loop is a fairly simple counting/iterating process, it might become more complicated than you want it to be. The while loop process would likely be more readable here, and readability should always come first. Given the availability of the while loop, the for loop is not really necessary at all, but it is available for those simple iterating conditions that start at a given place and stop at a given place.

So which one? It is generally accepted that for loops are used for simple counting actions, such as counting from one to some number of spaces to output, or to output a given number of letters or numbers. If it starts at a specific number and ends at a specific number, the for loop is your tool. However, if you will be testing each statement for some potentially changing condition and/or the starting or ending conditions won't always be clear, use a while loop. Do not favor one over the other for style purposes; use the one that gets the job done, and move on.

About declaring loop counters

One of the things you will notice frequently on the Internet and other assorted places that teach poor programming is the declaration of loop counters or variables inside the for loop. Here is an example:

for( int loopCounter = 0; loopCounter < someMaxValue; loopCounter++ )
{
// block code here
}

While this is pervasive, so was Disco at one time. It is very convenient for people who are hacking some kind of program together and don't know what they are going to do next, but that is not what you should be learning from this reference. From the outset, the practice of declaring variables here is very poor engineering of any kind, but in this case, it is very poor software engineering. Always (always, always) declare all of your variables at the beginning of your functions. That will represent superior engineering and discipline.

If someone is reviewing your code -- and if your code is any good, someone will be reviewing it -- and they see a variable used, they may need to backtrack it to see where it was initialized or modified. If they have to go through each for loop to find the variables, and from there have to figure which for loop declared which variable, they are costing the company money that the company does not want to spend. And by the way, it will also cost time you don't want to spend if you are the one trying to debug the program. Simple rule: Never declare variables in for loops. Better yet, never declare variables anywhere in any loop. And, as may have been mentioned previously, always declare variables in one block at the beginning of each function. Keep it simple, and keep your job.

The Process of Repetition, Continued (Again)

As mentioned, it would be very easy to write all your C programs with nothing but while loops. for loops are not really necessary, but there are some good places for them that will get a job done cleanly and still maintain high readability, and they do offer the benefit of showing most or all of the loop management activities in one place. The key to any programming process however, is to use the right tool for the right job, just like any other professional environment. If you have more than one way to accomplish your tasks, you have that much more ability to manage your problem solving activities.