6.3.
Loops
Use a loop to execute a
group
of statements, called the loop body, more than once. In C, you can introduce a loop by one of three
iteration statements
:
while
,
do ... while
, and
for
.
In each of these statements, the number of iterations through the loop body is controlled by a condition, the
controlling expression
. This is an expression of a scalar type; that is, an arithmetic expression or a pointer. The loop condition is true if the value of the controlling expression is not equal to 0;
otherwise
, it is
considered
false.
6.3.1. while Statements
A
while
statement executes a statement repeatedly as long as the controlling expression is true:
while (
expression
)
statement
The
while
statement is a
top-driven
loop: first the loop condition (i.e., the controlling expression) is evaluated. If it yields
true
, the loop body is executed, and then the controlling expression is evaluated again. If the condition is false, program execution continues with the statement following the loop body.
Syntactically, the loop body consists of one statement. If several statements are required, they are grouped in a block. Example 6-1 shows a simple
while
loop that reads in floating-point
numbers
from the console and accumulates a running total of them.
Example 6-1. A while loop
/* Read in numbers from the keyboard and
* print out their average.
* -------------------------------------- */
#include <stdio.h>
int main( )
{
double x = 0.0, sum = 0.0;
int count = 0;
printf( "\t--- Calculate Averages ---\n" );
printf( "\nEnter some numbers:\n"
"(Type a letter to end your input)\n" );
while ( scanf( "%lf", &x ) == 1 )
{
sum += x;
++count;
}
if ( count == 0 )
printf( "No input data!\n" );
else
printf( "The average of your numbers is %.2f\n", sum/count );
return 0;
}
In Example 6-1, the controlling expression:
scanf( "%lf", &x ) == 1
is true as long as the
user
enters a decimal number. As soon as the function
scanf( )
is unable to convert the string input into a floating-point numberwhen the user types the letter
q
, for example
scanf( )
returns the value 0 (or -1 for
EOF
, if the end of the input stream was reached or an error occurred). The condition is then false, and execution continues at the
if
statement that
follows
the loop body.
6.3.2. for Statements
Like the
while
statement, the
for
statement is a top-driven loop, but with more loop logic contained within the statement itself:
for ( [
expression1
]; [
expression2
]; [
expression3
] )
statement
The three actions that need to be executed in a typical loop are specified together at the top of the loop body:
-
expression1
: Initialization
-
Evaluated only once, before the first evaluation of the controlling expression, to perform any necessary initialization.
-
expression2
: Controlling expression
-
Tested
before each iteration. Loop execution ends when this expression
evaluates
to
false
.
-
expression3
: Adjustment
-
An adjustment, such as the incrementation of a counter, performed
after
each loop iteration, and before
expression2
is tested again.
Example 6-2 shows a
for
loop that initializes each element of an array.
Example 6-2. Initializing an array using a for loop
#define ARR_LENGTH 1000
/* ... */
long arr[ARR_LENGTH];
int i;
for ( i = 0; i < ARR_LENGTH; ++i )
arr[i] = 2*i;
Any of the three expressions in the head of the
for
loop can be omitted. This means that its shortest possible form is:
for ( ; ; )
A missing controlling expression is considered to be always true, and so defines an infinite loop .
The following form, with no initializer and no adjustment expression, is equivalent to
while (
expression
)
:
for ( ;
expression
; )
In fact, every
for
statement can also be rewritten as a
while
statement, and vice versa. For example, the complete
for
loop in Example 6-2 is equivalent to the following
while
loop:
i = 0; // Initialize the counter
while ( i < ARR_LENGTH ) // The loop condition
{
arr[i] = 2*i;
++i; // Increment the counter
}
for
is
generally
preferable to
while
when the loop contains a counter or index variable that needs to be
initialized
and then adjusted after each iteration.
In ANSI C99, a declaration can also be used in place of
expression1
. In this case, the scope of the variable declared is limited to the
for
loop. For example:
for ( int i = 0; i < ARR_LENGTH; ++i )
arr[i] = 2*i;
The variable
i
declared in this
for
loop, unlike that in Example 6-2, no longer exists after the end of the
for
loop.
The comma operator is often used in the head of a
for
loop in order to assign initial values to more than one variable in
expression1
, or to adjust several
variables
in
expression3
. For example, the function
strReverse( )
shown here uses two index variables to reverse the order of the
characters
in a string:
void strReverse( char* str)
{
char ch;
for ( int i = 0, j = strlen(str)-1; i < j; ++i, --j )
ch = str[i], str[i] = str[j], str[j] = ch;
}
The comma operator can be used to evaluate additional expressions where only one expression is permitted. See "Other Operators" in Chapter 5 for a detailed description of the comma operator.
6.3.3. do...while Statements
The
do ... while
statement is a
bottom-driven
loop:
do
statement
while (
expression
);
The loop body statement is executed once before the controlling
expression
is evaluated for the first time. Unlike the
while
and
for
statements,
do ... while
ensures that at least one iteration of the loop body is performed. If the controlling expression yields
true
, then another iteration follows. If
false
, the loop is finished.
In Example 6-3, the functions for reading and processing a command are called at least once. When the user exits the menu system, the function
getCommand( )
returns the value of the constant
END
.
Example 6-3. do...while
// Read and carry out an incoming menu command.
// --------------------------------------------
int getCommand( void );
void performCommand( int cmd );
#define END 0
/* ... */
do
{
int command = getCommand( ); // Poll the menu system.
performCommand( command ); // Execute the command received.
} while ( command != END );
Example 6-4 shows a version of the standard library function
strcpy
( )
, with just a simple statement rather than a block in the loop body. Because the loop condition is tested after the loop body, the copy operation includes the string terminator
'\0'
.
Example 6-4. A strcpy( ) function using do ... while
// Copy string s2 to string s1.
// ----------------------------
char *strcpy( char* restrict s1, const char* restrict s2 )
{
int i = 0;
do
s1[i] = s2[i]; // The loop body: copy each character
while ( s2[i++] != '
// Copy string s2 to string s1. // ---------------------------- char *strcpy( char* restrict s1, const char* restrict s2 ) { int i = 0; do s1[i] = s2[i]; // The loop body: copy each character while ( s2[i++] != '\0' ); // End the loop if we just
copied
a '\0'. return s1; }
' ); // End the loop if we just copied a '
// Copy string s2 to string s1. // ---------------------------- char *strcpy( char* restrict s1, const char* restrict s2 ) { int i = 0; do s1[i] = s2[i]; // The loop body: copy each character while ( s2[i++] != '\0' ); // End the loop if we just
copied
a '\0'. return s1; }
'.
return s1;
}
6.3.4. Nested Loops
A loop body can be any simple or block statement, and may include other loop statements. Example 6-5 is an implementation of the bubble-
sort
algorithm using nested loops. The inner loop in this algorithm inspects the entire array on each iteration, swapping neighboring elements that are out of order. The outer loop is reiterated until the inner loop finds no elements to swap. After each iteration of the inner loop, at least one element has been moved to its correct position. Hence the remaining length of the array to be sorted,
len
, can be reduced by one.
Example 6-5. Nested loops in the bubble-sort algorithm
// Sort an array of float in ascending order
// using the bubble-sort algorithm.
// -----------------------------------------
void bubbleSort( float arr[ ], int len ) // The array arr and
{ // its length len.
int isSorted = 0;
do
{
float temp; // Holder for values being swapped.
isSorted = 1;
--len;
for ( int i = 0; i < len; ++i )
if
( arr[i] > arr[i+1] )
{
isSorted = 0; // Not finished yet.
temp = arr[i]; // Swap adjacent values.
arr[i] = arr[i+1];
arr[i+1] = temp;
}
} while ( !isSorted );
}
Note that the automatic variables
temp
, declared in the
do ... while
loop, and
i
, declared in the head of the
for
loop, are created and
destroyed
again on each iteration of the outer loop.
|