CHAPTER 4

Loops

In the last chapter you learned how to compare items and base your decisions on the result. You were able to choose how the computer reacted based on the input to a program. In this chapter, you'll learn how you can repeat a block of statements until some condition is met. This is called a loop.

The number of times that a loop is repeated can be controlled simply by a count—repeating the statement block a given number of times—or it can be more complex—repeating a block until some condition is met, such as the user entering quit, for instance. The latter would enable you to program the calculator example in the previous chapter to repeat as many times as required without having to use a goto statement.

In this chapter, you'll learn the following:

  • How you can repeat a statement, or a block of statements, as many times as you want
  • How you can repeat a statement or a block of statements until a particular condition is fulfilled
  • How you use the for, while, and do-while loops
  • What the increment and decrement operators do, and how you can use them
  • How you can write a program that plays a Simple Simon game

How Loops Work

As I said, the programming mechanism that executes a series of statements repeatedly a given number of times, or until a particular condition is fulfilled, is called a loop. The loop is a fundamental programming tool, along with the ability to compare items. Once you can compare data values and repeat a block of statements, you can combine these capabilities to control how many times the block of statements is executed. For example, you can keep performing a particular action until two items that you are comparing are the same. Once they are the same, you can go on to perform a different action.

In the lottery example in Chapter 3 in Program 3.8, you could give the user exactly three guesses—in other words, you could let him continue to guess until a variable called number_of_guesses, for instance, equals 3. This would involve a loop to repeat the code that reads a guess from the keyboard and checks the accuracy of the value entered. Figure 4-1 illustrates the way a typical loop would work in this case.

More often than not, you'll find that you want to apply the same calculation to different sets of data values. Without loops, you would need to write out the instructions to be performed as many times as there were sets of data values to be processed, which would not be very satisfactory. A loop allows you to use the same program code for any number of sets of data to be entered.

image

Figure 4-1. Logic of a typical loop

Before I discuss the various types of loops that you have available in C, I'll first introduce two new arithmetic operators that you'll encounter frequently in C programs: the increment operator and the decrement operator. These operators are often used with loops, which is why I'll discuss them here. I'll start with the briefest of introductions to the increment and decrement operators and then go straight into an example of how you can use them in the context of a loop. Once you're comfortable with how loops work, you'll return to the increment and decrement operators to investigate some of their idiosyncrasies.

Introducing the Increment and Decrement Operators

The increment operator (++) and the decrement operator () will increment or decrement the value stored in the integer variable that they apply to by 1. Suppose you have defined an integer variable, number, that currently has the value 6. You can increment it by 1 with the following statement:

++number;                              /* Increase the value by 1 */

After executing this statement, number will contain the value 7. Similarly, you could decrease the value of number by one with the following statement:

--number;                              /* Decrease the value by 1 */

These operators are different from the other arithmetic operators you have encountered. When you use any of the other arithmetic operators, you create an expression that will result in a value, which may be stored in a variable or used as part of a more complex expression. They do not directly modify the value stored in a variable. When you write the expression -number, for instance, the result of evaluating this expression is 6 if number has the value +6, but the value stored in number is unchanged. On the other hand, the expression --number does modify the value in number. This expression will decrement the value in number by 1, so number will end up as 5 if it was originally 6.

There's much more you'll need to know about the increment and decrement operators, but I'll defer that until later. Right now, let's get back to the main discussion and take a look at the simplest form of loop, the for loop. There are other types of loops as you'll see later, but I'll give the for loop a larger slice of time because once you understand it the others will be easy.

The for Loop

You can use the for loop in its basic form to execute a block of statements a given number of times. Let's suppose you want to display the numbers from 1 to 10. Instead of writing ten printf() statements, you could write this:

int count;
for(count = 1 ; count <= 10 ; ++count)
  printf(" %d", count);

The for loop operation is controlled by the contents of the parentheses that follow the keyword for. This is illustrated in Figure 4-2. The action that you want to repeat each time the loop repeats is the statement immediately following the first line that contains the keyword for. Although you have just a single statement here, this could equally well be a block of statements between braces.

Figure 4-2 shows the three control expressions that are separated by semicolons and that control the operation of the loop.

image

Figure 4-2. Control expressions in a for loop

The effect of each control expression is shown in Figure 4-2, but let's take a much closer look at exactly what's going on.

  • The first control expression is executed only once, when the loop starts. In the example, the first expression sets a variable, count, to 1. This is the expression count = 1.
  • The second control expression must be a logical expression that produces a result of true or false; in this case, it's the expression count <= 10. The second expression is evaluated before each loop iteration starts. If the expression evaluates to true, the loop continues, and if it's false, the loop ends and execution of the program continues with the first statement following the loop block or loop statement. Remember that false is a zero value, and any nonzero value is true. Thus, the example loop will execute the printf() statement as long as count is less than or equal to 10. The loop will end when count reaches 11.
  • The third control expression, ++count in this case, is executed at the end of each iteration. Here you use the increment operator to add 1 to the value of count. On the first iteration, count will be 1, so the printf() will output 1. On the second iteration, count will have been incremented to 2, so the printf() will output the value 2. This will continue until the value 10 has been displayed. At the start of the next iteration, count will be incremented to 11, and because the second control expression will then be false, the loop will end.

Notice the punctuation. The for loop control expressions are contained within parentheses, and each expression is separated from the next by a semicolon. You can omit any of the control expressions, but if you do you must still include the semicolon. For example, you could declare and initialize the variable count to 1 outside the loop:

int count = 1;

Now you don't need to specify the first control expression at all, and the for loop could look like this:

for( ; count <= 10 ; ++count)
  printf(" %d", count);

As a trivial example, you could make this into a real program simply by adding a few lines of code:

/* Program 4.1 List ten integers */
#include <stdio.h>

int main(void)
{
  int count = 1;
  for( ; count <= 10 ; ++count)
    printf(" %d", count);
  printf(" We have finished. ");
  return 0;
}

This program will list the numbers from 1 to 10 on separate lines and then output this message:


We have finished.

The flow chart in Figure 4-3 illustrates the logic of this program.

image

Figure 4-3. The logic of Program 4.1

In this example, it's easy to see what the variable count starts out as, so this code is quite OK. In general, though, unless the variable controlling the loop is initialized very close to the loop statement itself, it's better to initialize it in the first control expression. That way, there's less potential for error.

You can also declare the loop variable within the first loop control expression, in which case the variable is local to the loop and does not exist once the loop has finished. You could write the main() function like this:

int main(void)
{
  for(int count = 1 ; count <= 10 ; ++count)
    printf(" %d", count);
  printf(" We have finished. ");
  return 0;
}

Now count is declared within the first for loop expression. This means that count does not exist once the loop ends, so you could not output its value after the loop. When you really do need access to the loop control variable outside the loop, you just declare it in a separate statement preceding the loop, as in Program 4.1.

Let's try a slightly different example.

General Syntax of the for Loop

The general pattern of the for loop is as follows:

for(starting_condition; continuation_condition ; action_per_iteration)
  Statement;

Next_statement;

The statement to be repeated is represented by Statement. In general, this could equally well be a block of statements (a group of statements) enclosed between a pair of braces.

The starting_condition usually (but not always) sets an initial value to a loop control variable. The loop control variable is typically, but not necessarily, a counter of some kind that tracks how often the loop has been repeated. You can also declare and initialize several variables of the same type here with the declarations separated by commas; in this case all the variables will be local to the loop and will not exist once the loop ends.

The continuation_condition is a logical expression evaluating to true or false. This determines whether the loop should continue to be executed. As long as this condition has the value true, the loop continues. It typically checks the value of the loop control variable, but any logical expression can be placed here, as long as you know what you're doing.

As you've already seen, the continuation_condition is tested at the beginning of the loop rather than at the end. This obviously makes it possible to have a for loop whose statements aren't executed at all if the continuation_condition starts out as false.

The action_per_iteration is executed at the end of each loop iteration and is usually (but again not necessarily) an increment or decrement of one or more loop control variables. Where several variables are modified, you separate the expression by commas. At each iteration of the loop, the statement or block of statements immediately following the for statement is executed. The loop is terminated, and execution continues with Next_statement as soon as the continuation_condition is false.

Here's an example of a loop with two variables declared in the first loop control condition:

for(int i = 1, j = 2 ; i<=5 ; i++, j = j+2)
  printf(" %5d", i*j);

The output produced by this fragment will be the values 2, 8, 18, 32, and 50 on separate lines.

More on the Increment and Decrement Operators

Now that you've seen an increment operator in action, let's delve a little deeper and find out what else these increment and decrement operators can do. They're both unary operators, which means that they're used with only one operand. You know they're used to increment (increase) or decrement (decrease) a value stored in a variable of one of the integer types by 1.

The Increment Operator

Let's start with the increment operator. It takes the form ++ and adds 1 to the variable it acts on. For example, assuming your variables are of type int, the following three statements all have exactly the same effect:

count = count + 1;
count += 1;
++count;

Each of these statement increments the variable count by 1. The last form is clearly the most concise.

Thus, if you declare a variable count and initialize it to 1

int count = 1;

and then you repeat the following statement six times in a loop

++count;

by the end of the loop, count will have a value of 7.

You can also use the increment operator in an expression. The action of this operator in an expression is to increment the value of the variable and then use the incremented value in the expression. For example, suppose count has the value 5 and you execute the statement

total = ++count + 6;

The variable count will be incremented to 6 and the variable total will be assigned the value 12, so the one statement modifies two variables. The variable count, with the value 5, has 1 added to it, making it 6, and then 6 is added to this value to produce 12 for the expression on the right side of the assignment operator. This value is stored in total.

The Prefix and Postfix Forms of the Increment Operator

Up to now you've written the operator ++ in front of the variable to which it applies. This is called the prefix form. The operator can also be written after the variable to which it applies, and this is referred to as the postfix form. In this case, the effect is significantly different from the prefix form when it's used in an expression. If you write count++ in an expression, the incrementing of the variable count occurs after its value has been used. This sounds more complicated than it is.

Let's look at a variation on the earlier example:

total = 6 + count++;

With the same initial value of 5 for count, total is assigned the value 11. This is because the initial value of count is used to evaluate the expression on the right of the assignment (6 + 5). The variable count is incremented by 1 after its value has been used in the expression. The preceding statement is therefore equivalent to these two statements:

total = 6 + count;
++count;

Note, however, that when you use the increment operator in a statement by itself (as in the preceding second statement, which increments count), it doesn't matter whether you write the prefix or the postfix version of the operator. They both have the same effect.

Where you have an expression such as a++ + b—or worse, a+++b—it's less than obvious what is meant to happen or what the compiler will achieve. The expressions are actually the same, but in the second case you might really have meant a + ++b, which is different because it evaluates to one more than the other two expressions.

For example, if a = 10 and b = 5, then in the statement

x = a++ + b;

x will have the value 15 (from 10 + 5) because a is incremented after the expression is evaluated. The next time you use the variable a, however, it will have the value 11.

On the other hand, if you execute the following statement, with the same initial values for a and b

y = a + (++b);

y will have the value 16 (from 10 + 6) because b is incremented before the statement is evaluated.

It's a good idea to use parentheses in all these cases to make sure there's no confusion. So you should write these statements as follows:

x = (a++) + b;
y = a + (++b);

The Decrement Operator

The decrement operator works in much the same way as the increment operator. It takes the form -- and subtracts 1 from the variable it acts on. It's used in exactly the same way as ++. For example, assuming the variables are of type int, the following three statements all have exactly the same effect:

count = count - 1;
count -= 1;
--count;

They each decrement the variable count by 1. For example, if count has the value 10, then the statement

total = --count + 6;

results in the variable total being assigned the value 15 (from 9 + 6). The variable count, with the initial value of 10, has 1 subtracted from it so that its value is 9. Then 6 is added to the new value, making the value of the expression on the right of the assignment operator 15.

Exactly the same rules that I discussed in relation to the prefix and postfix forms of the increment operator apply to the decrement operator. For example, if count has the initial value 5, then the statement

total = --count + 6;

results in total having the value 10 (from 4 + 6) assigned, whereas

total = 6 + count-- ;

sets the value of total to 11 (from 6 + 5). Both operators are usually applied to integers, but you'll also see, in later chapters, how they can be applied to certain other data types in C.

The for Loop Revisited

Now that you understand a bit more about ++ and --, let's move on with another example that uses a loop.

As I've hinted by saying "not necessarily" in my descriptions of how the for loop is controlled, there is a lot of flexibility about what you can use as control expressions. The next program demonstrates how this flexibility might be applied to shortening the previous example slightly.

Modifying the for Loop Variable

Of course, you aren't limited to incrementing the loop control variable by 1. You can change it by any value, positive or negative. You could sum the first n integers backward if you wish, as in the following example:

/* Program 4.5 Summing integers backward */ #include <stdio.h>
int main(void)
{
  long sum = 0L;                  /* Stores the sum of the integers      */
  int count = 0;                  /* The number of integers to be summed */

  /* Read the number of integers to be summed */
  printf(" Enter the number of integers you want to sum: ");
  scanf(" %d", &count);

  /* Sum integers from count to 1 */
  for(int i = count ; i >= 1 ; sum += i--);

  printf(" Total of the first %d numbers is %ld ", count, sum);
  return 0;
}

This produces the same output as the previous example. The only change is in the loop control expressions. The loop counter is initialized to count, rather than to 1, and it's decremented on each iteration. The effect is to add the values count, count-1, count-2, and so on, down to 1. Again, if you used the prefix form, the answer would be wrong, because you would start with adding count-1 instead of just count.

Just to keep any mathematically inclined readers happy, I should mention that it's quite unnecessary to use a loop to sum the first n integers. The following tidy little formula for the sum of the integers from 1 to n will do the trick much more efficiently:

n*(n+1)/2

However, it wouldn't teach you much about loops, would it?

A for Loop with No Parameters

As I've already mentioned, you have no obligation to put any parameters in the for loop statement at all. The minimal for loop looks like this:

for( ;; )
  statement;

Here, as previously, statement could also be a block of statements enclosed between braces, and in this case it usually will be. Because the condition for continuing the loop is absent, as is the initial condition and the loop increment, the loop will continue indefinitely. As a result, unless you want your computer to be indefinitely doing nothing, statement must contain the means of exiting from the loop. To stop repeating the loop, the loop body must contain two things: a test of some kind to determine whether the condition for ending the loop has been reached, and a statement that will end the current loop iteration and continue execution with the statement following the loop.

The break Statement in a Loop

You encountered the break statement in the context of the switch statement in Chapter 3. Its effect was to stop executing the code within the switch block and continue with the first statement following the switch. The break statement works in essentially the same way within the body of a loop—any kind of loop. For instance

char answer = 0;
for( ;; )
{
  /* Code to read and process some data */
  printf("Do you want  to enter some more(y/n): ");
  scanf("%c", &answer);
  if(tolower(answer) == 'n')
    break;                             /* Go to statement after the loop */
}
/* Statement after the loop */

Here you have a loop that will execute indefinitely. The scanf() statement reads a character into answer, and if the character entered is n or N, the break statement will be executed. The effect is to stop executing the loop and to continue with the first statement following the loop. Let's see this in action in another example.

Limiting Input Using a for Loop

You can use a for loop to limit the amount of input from the user. Each iteration of the loop will permit some input to be entered. When the loop has completed a given number of iterations, the loop ends so no more data can be entered. You can write a simple program to demonstrate how this can work. The program will implement a guessing game.

Generating Pseudo-Random Integers

The previous example would have been much more entertaining if the number to be guessed could have been generated within the program so that it was different each time the program executed. Well, you can do that using the rand() function that's declared in the <stdlib.h> header file:

int chosen = 0;
chosen = rand();  /* Set to a random integer */

Each time you call the rand() function, it will return a random integer. The value will be from 0 to a maximum of RAND_MAX, the value of which is defined in <stdlib.h>. The integers generated by the rand() function are described as pseudo-random numbers because truly random numbers can arise only in natural processes and can't be generated algorithmically.

The sequence of numbers that's generated by the rand() function uses a starting seed number, and for a given seed the sequence will always be the same. If you use the function with the default seed value, as in the previous snippet, you'll always get exactly the same sequence, which won't make the game very challenging but is useful when you are testing a program. However, C provides another standard function, srand(), which you can call to initialize the sequence with a particular seed that you pass as an argument to the function. This function is also declared in the <stdlib.h> header.

At first sight, this doesn't seem to get you much further with the guessing game, as you now need to generate a different seed each time the program executes. Yet another library function can help with this: the time() function that's declared in the <time.h> header file. The time() function returns the number of seconds that have elapsed since January 1, 1970, as an integer, and because time always marches on, you can get a different value returned by the time() function each time the program executes. The time() function requires an argument to be specified that you'll specify as NULL. NULL is a symbol that's defined in <stdlib.h>, but I'll defer further discussion of it until Chapter 7.

Thus to get a different sequence of pseudo-random numbers each time a program is run, you can use the following statements:

srand(time(NULL));                     /* Use clock value as starting seed */
int chosen = 0;
chosen = rand();                  /* Set to a random integer 0 to RAND_MAX */

The value of the upper limit, RAND_MAX, is likely to be quite large—often the maximum value that can be stored as type int. When you need a more limited range of values, you can scale the value returned by rand() to provide values within the range that you want. Suppose you want to obtain values in a range from 0 up to, but not including, limit. The simplest approach to obtaining values in this range is like this:

srand(time(NULL));                     /* Use clock value as starting seed     */
int limit = 20.0;                      /* Upper limit for pseudo-random values */
int chosen = 0;
chosen = rand()%limit;                 /* 0 to limit-1 inclusive               */

Of course, if you want numbers from 1 to limit, you can write this:

chosen = 1+rand()%limit;               /* 1 to limit   inclusive               */

This works reasonably well with the implementation of rand() in my compiler and library. However, this isn't a good way in general of limiting the range of numbers produced by a pseudo-random number generator. This is because you're essentially chopping off the high-order bits in the value that's returned and implicitly assuming that the bits that are left will also represent random values. This isn't necessarily the case.

You could try using rand() in a variation of the previous example:

/*  Program 4.7A  A More Interesting Guessing Game */ #include <stdio.h>
#include <stdlib.h>               /* For rand() and srand() */
#include <time.h>                 /* For time() function    */
int main(void)
{
  int chosen = 0;                 /* The lucky number                     */
  int guess = 0;                  /* Stores a guess                         */
  int count = 3;                  /* The maximum number of tries            */
  int limit = 20;                 /* Upper limit for pseudo-random values */

  srand(time(NULL));              /* Use clock value as starting seed     */
  chosen = 1 + rand()%limit;      /* Random int 1 to limit                */

  printf(" This is a guessing game.");
  printf(" I have chosen a number between 1 and 20"
                                      " which you must guess. ");

  for( ; count>0 ; —count)
  {
    printf(" You have %d tr%s left.", count, count == 1 ? "y" : "ies");
    printf(" Enter a guess: ");      /* Prompt for a guess  */
    scanf("%d", &guess);              /* Read in a guess     */

    /* Check for a correct guess */
    if(guess == chosen)
    {
      printf(" You guessed it! ");
      return 0;                       /* End the program */
    }

    /* Check for an invalid guess */
    if(guess<1 || guess > 20)
      printf("I said between 1 and 20. ");
    else
      printf("Sorry. %d is wrong. ", guess);
  }
   printf(" You have had three tries and failed. The number was %ld ",
                                                                 chosen);
  return 0;
}

This program should give you a different number to guess most of the time.

More for Loop Control Options

You've seen how you can increment or decrement the loop counter by 1 using the ++ and -- operators. You can increment or decrement the loop counter by any amount that you wish. Here's an example of how you can do this:

long sum = 0L;
for(int n = 1 ; n<20 ; n += 2)
  sum += n;
printf("Sum is %ld", sum);

The loop in the preceding code fragment sums all the odd integers from 1 to 20. The third control expression increments the loop variable n by 2 on each iteration. You can write any expression here, including any assignment. For instance, to sum every seventh integer from 1 to 1000, you could write the following loop:

for(int n = 1 ; n<1000 ; n = n+7)
  sum += n;

Now the third loop control expression increments n by 7 at the end of each iteration, so you'll get the sum 1 + 8 + 15 + 22 + and so on up to 1000.

You aren't limited to a single loop control expression. You could rewrite the loop in the first code fragment, summing the odd numbers from 1 to 20, like this:

for(int n = 1 ; n<20 ; sum += n, n += 2)
  ;

Now the third control expression consists of two expressions separated by a comma. These will execute in sequence at the end of each loop iteration. So first the expression

sum +=n

will add the current value of n to sum. Next, the second expression

n += 2

will increment n by 2. Because these expressions execute in sequence from left to right, you must write them in the sequence shown. If you reverse the sequence, the result will be incorrect.

You aren't limited to just two expressions either. You can have as many expressions here as you like, as long as they're separated by commas. Of course, you should make use of this only when there is a distinct advantage in doing so. Too much of this can make your code hard to understand.

The first and second control expressions can also consist of several expressions separated by commas, but the need for this is quite rare.

Floating-Point Loop Control Variables

The loop control variable can also be a floating-point variable. Here's a loop to sum the fractions from 1/1 to 1/10:

double sum = 0.0;
for(double x = 1.0 ; x<11 ; x += 1.0)
  sum += 1.0/x;

You'll find this sort of thing isn't required very often. It's important to remember that fractional values often don't have an exact representation in floating-point form, so it's unwise to rely on equality as the condition for ending a loop, for example

for(double x = 0.0 ; x != 2.0 ; x+= 0.2)      /* Indefinite loop!!! */
  printf(" x = %.2lf",x);

This loop is supposed to output the values of x from 0.0 to 2.0 in steps of 0.2, so there should be 11 lines of output. Because 0.2 doesn't have an exact representation as a binary floating-point value, x never has the value 2.0, so this loop will take over your computer and run indefinitely (until you stop it; use Ctrl+C under Microsoft Windows).

The while Loop

That's enough of the for loop. Now that you've seen several examples of for loops, let's look at a different kind of loop: the while loop. With a while loop, the mechanism for repeating a set of statements allows execution to continue for as long as a specified logical expression evaluates to true. In English, I could represent this as follows:

While this condition is true
  Keep on doing this

Alternatively, here's a particular example:

While you are hungry
  Eat sandwiches

This means that you ask yourself "Am I hungry?" before eating the next sandwich. If the answer is yes, then you eat a sandwich and then ask yourself "Am I still hungry?" You keep eating sandwiches until the answer is no, at which point you go on to do something else—drink some coffee, maybe. One word of caution: enacting a loop in this way yourself is probably best done in private.

The general syntax for the while loop is as follows:

while( expression )
  Statement1;

  Statement2;

As always, Statement1 could be a block of statements.

The logic of the while loop is shown in Figure 4-5.

image

Figure 4-5. The logic of the while loop

Just like the for loop, the condition for continuation of the while loop is tested at the start, so if expression starts out false, none of the loop statements will be executed. If you answer the first question "`No, I'm not hungry," then you don't get to eat any sandwiches at all, and you move straight on to the coffee.

Nested Loops

Sometimes you may want to place one loop inside another. You might want to count the number of occupants in each house on a street. You step from house to house, and for each house you count the number of occupants. Going through all the houses could be an outer loop, and for each iteration of the outer loop you would have an inner loop that counts the occupants.

The simplest way to understand how a nested loop works is to look at a simple example.

Nested Loops and the goto Statement

You've learned how you can nest one loop inside another, but it doesn't end there. You can nest as many loops one inside another as you want, for instance

for(int i = 0 ; i<10 ; ++i)
  for(int j = 0 ; j<20 ; ++k)          /* Loop executed 10 times            */
    for(int k = 0 ; k<30 ; ++k)        /* Loop executed 10x20 times         */
    {                                  /* Loop body executed 10x20x30 times */
       /* Do something useful */
    }

The inner loop controlled by j will execute once for each iteration of the outer loop that is controlled by i. The innermost loop controlled by k will execute once for each iteration of the loop controlled by j. Thus the body of the innermost loop will be executed 6,000 times.

Occasionally with deeply nested loops like this you'll want to break out of all the nested loops from the innermost loop and then continue with the statement following the outermost loop. A break statement in the innermost loop will only break out of that loop, and execution will continue with the loop controlled by j. To escape the nested loops completely using break statements therefore requires quite complicated logic to break out of each level until you escape the outermost loop. This is one situation in which the goto can be very useful because it provides a way to avoid all the complicated logic. For example

for(int i = 0 ; i<10 ; ++i)
  for(int j = 0 ; j<20 ; ++k)          /* Loop executed 10 times            */
    for(int k = 0 ; k<30 ; ++k)        /* Loop executed 10x20 times         */
    {                                  /* Loop body executed 10x20x30 times */
       /* Do something useful */
       if(must_escape)
         goto out;
    }
out: /*Statement following the nested loops */

This fragment presumes that must_escape can be altered within the innermost loop to signal that the whole nested loop should end. If the variable must_escape is true, you execute the goto statement to branch directly to the statement with the label out. So you have a direct exit from the complete nest of loops without any complicated decision-making in the outer loop levels.

The do-while Loop

The third type of loop is the do-while loop. Now you may be asking why you need this when you already have the for loop and the while loop. Well, there's actually a very subtle difference between the do-while loop and the other two. The test for whether the loop should continue is at the end of the loop so the loop statement or statement block always executes at least once.

The while loop tests at the beginning of the loop. So before any action takes place, you check the expression. Look at this fragment of code:

int number = 4;

while(number < 4)
{
  printf(" Number = %d", number);
  number++;
}

Here, you would never output anything. The control expression number < 4 is false from the start, so the loop block is never executed.

The do-while loop, however, works differently. You can see this if you replace the preceding while loop with a do-while loop and leave the rest of the statements the same:

int number = 4;

do
{
  printf(" Number = %d", number);
  number++;
}
while(number < 4);

Now when you execute this loop, you get number = 4 displayed. This is because the expression number < 4 is only checked at the end of the first iteration of the loop.

The general representation of the do-while loop is as follows:

do
  Statement;
while(expression);

Notice the semicolon after the while statement in a do-while loop. There isn't one in the while loop. As always, a block of statements between braces can be in place of Statement. In a do-while loop, if the value of expression is true (nonzero), the loop continues. The loop will exit only when the value of expression becomes false (zero). You can see how this works more clearly in Figure 4-6.

Here, you can see that you eat a sandwich before you check whether you're hungry. You'll always eat at least one sandwich so this loop is not to be used as part of a calorie-controlled diet.

image

Figure 4-6. Operation of the do-while loop

The continue Statement

Sometimes a situation will arise in which you don't want to end a loop, but you want to skip the current iteration and continue with the next. The continue statement in the body of a loop does this and is written simply as follows:

continue;

Of course, continue is a keyword, so you must not use it for other purposes. Here's an example of how the continue statement works:

for(int day = 1; day<=7 ; ++day)
{
  if(day == 3)
    continue;
  /* Do something useful with day */
}

This loop will execute with values of day from 1 to 7. When day has the value 3, however, the continue statement will execute, and the rest of the current iteration is skipped and the loop continues with the next iteration when day will be 4.

You'll see more examples of using continue later in the book.

Designing a Program

It's time to try your skills on a bigger programming problem and to apply some of what you've learned in this chapter and the previous chapters. You'll also see a few new standard library functions that you're sure to find useful.

The Problem

The problem that you're going to solve is to write a game of Simple Simon. Simple Simon is a memory-test game. The computer displays a sequence of digits on the screen for a short period of time. You then have to memorize them, and when the digits disappear from the screen, you must enter exactly the same sequence of digits. Each time you succeed, you can repeat the process to get a longer list of digits for you to try. The objective is to continue the process for as long as possible.

The Analysis

The program must generate a sequence of integers between 0 and 9 and display the sequence on the screen for one second before erasing it. The player then has to try to enter the identical sequence of digits. The sequences gradually get longer until the player gets a sequence wrong. A score is then calculated based on the number of successful tries and the time taken, and the player is asked if he would like to play again.

The logic of the program is quite straightforward. You could express it in general terms in the flow chart shown in Figure 4-7.

image

Figure 4-7. The basic logic of the Simple Simon program

Each box describes an action in the program, and the diamond shapes represent decisions. Let's use the flow chart as the basis for coding the program.

The Solution

This section outlines the steps you'll take to solve the problem.

Step 1

You can start by putting in the main loop for a game. The player will always want to have at least one game, so the loop check should go at the end of the loop. The do-while loop fits the bill very nicely. The initial program code will be this:

/* Program 4.12 Simple Simon */
#include <stdio.h>                     /* For input and output   */
#include <ctype.h>                     /* For toupper() function */

int main(void)
{
  /* Records if another game is to be played */
  char another_game = 'Y';

  /* Rest of the declarations for the program */

  /* Describe how the game is played */
  printf(" To play Simple Simon, ");
  printf("watch the screen for a sequence of digits.");
  printf(" Watch carefully, as the digits are only displayed"
                                                " for a second! ");
  printf(" The computer will remove them, and then prompt you ");
  printf("to enter the same sequence.");
  printf(" When you do, you must put spaces between the digits. ");
  printf(" Good Luck! Press Enter to play ");
  scanf("%c", &another_game);

  /* One outer loop iteration is one game */
  do
  {
    /* Code to play the game */

    /* Output the score when the game is finished */

    /* Check if a new game is required */
    printf(" Do you want to play again (y/n)? ");
    scanf("%c", &another_game);
  } while(toupper(another_game) == 'Y'),
  return 0;
}

As long as the player enters y or Y at the end of a game, she will be able to play again. Note how you can automatically concatenate two strings in the printf() statement:

printf(" Watch carefully, as the digits are only displayed"
                                                   " for a second! ");

This is a convenient way of splitting a long string over two or more lines. You just put each piece of the string between its own pair of double-quote characters, and the compiler will take care of assembling them into a single string.

Step 2

Next, you can add a declaration for another variable, called correct, that you'll need in the program to record whether the entry from the player is correct or not. You'll use this variable to control the loop that plays a single game:

/* Program 4.12 Simple Simon */
#include <stdio.h>                     /* For input and output    */
#include <ctype.h>                     /* For toupper() function  */
#include <stdbool.h>                 /* For bool, true, false  */
int main(void)
{
  /* Records if another game is to be played */
  char another_game = 'Y';

  /* true if correct sequence entered, false otherwise */   bool correct = true;
  /* Rest of the declarations for the program */

  /* Describe how the game is played */
  printf(" To play Simple Simon, ");
  printf("watch the screen for a sequence of digits.");
  printf(" Watch carefully, as the digits are only displayed"
                                                " for a second! ");
  printf(" The computer will remove them, and then prompt you ");
  printf("to enter the same sequence.");
  printf(" When you do, you must put spaces between the digits. ");
  printf(" Good Luck! Press Enter to play ");
  scanf("%c", &another_game);

  /* One outer loop iteration is one game */
  do
  {
    correct = true;          /* By default indicates correct sequence entered */
    /* Other code to initialize the game */
    /* Inner loop continues as long as sequences are entered correctly */     while(correct)     {       /* Play the game */     }
    /* Output the score when the game is finished */

    /* Check if new game required*/
    printf(" Do you want to play again (y/n)? ");
    scanf("%c", &another_game);
  } while(toupper(another_game) == 'Y'),
  return 0;
}

You are using the _Bool variable, correct, here, but because you have added an #include directive for the <stdbool.h> header, you can use bool as the type name. The <stdbool.h> header also defines the symbols true and false to correspond to 1 and 0 respectively.


Caution The code will compile as it is, and you should compile it to check it out, but you should not run it yet. As you develop your own programs, you'll want to make sure that the code will at least compile along each step of the way. If you wrote all the program code in one attempt, you could end up with hundreds of errors to correct, and as you correct one problem, more may appear. This can be very frustrating. By checking out the program incrementally, you can minimize this issue, and the problems will be easier to manage. This brings us back to our current program. If you run this, your computer will be completely taken over by the program, because it contains an infinite loop. The reason for this is the inner while loop. The condition for this loop is always true because the loop doesn't do anything to change the value of correct. However, you'll be adding that bit of the program shortly.


Step 3

Now you have a slightly more difficult task to do: generating the sequence of random digits. There are two problems to be tackled here. The first is to generate the sequence of random digits. The second is to check the player's input against the computer-generated sequence.

The main difficulty with generating the sequence of digits is that the numbers have to be random. You've already seen that you have a standard function, rand(), available that returns a random integer each time you call it. You can get a random digit by just getting the remainder after dividing by 10, by using the % operator.

To ensure that you get a different sequence each time the program is executed, you'll also need to call srand() to initialize the sequence with the value returned by the time() function in the way you've already seen. Both the rand() and srand() functions require that you include the <tdlib.h> header file into the program, and the time() function requires an #include directive for <time.h>.

Now let's think about this a bit more. You'll need the sequence of random digits twice: once to display it initially before you erase it, and the second time to check against the player's input. You could consider saving the sequence of digits as an integer value of type unsigned long long. The problem with this is that the sequence could get very long if the player is good, and it could exceed the upper limit for integer values of type unsigned long long. There is another possible approach. The rand() function can produce the same sequence of numbers twice. All you need to do is to start the sequence each time with the same seed by calling srand(). This means that you won't need to store the sequence of numbers. You can just generate the same sequence twice.

Now let's add some more code to the program, which will generate the sequence of random digits and check them against what the player enters:

/* Program 4.12 Simple Simon */
#include <stdio.h>                     /* For input and output    */
#include <ctype.h>                     /* For toupper() function  */
#include <stdbool.h>                   /* For bool, true, false   */
#include <stdlib.h>                    /* For rand() and srand() */ #include <time.h>                      /* For time() function    */
int main(void)
{
   /* Records if another game is to be played */
   char another_game = 'Y';
/* true if correct sequence entered, false otherwise */
  bool correct = true;

  /* Number of sequences entered successfully */   int counter = 0;
  int sequence_length = 0;       /* Number of digits in a sequence        */   time_t seed = 0;               /* Seed value for random number sequence */   int number = 0;                /* Stores an input digit                 */
  /* Rest of the declarations for the program */

  /* Describe how the game is played */
  printf(" To play Simple Simon, ");
  printf("watch the screen for a sequence of digits.");
  printf(" Watch carefully, as the digits are only displayed"
                                                " for a second! ");
  printf(" The computer will remove them, and then prompt you ");
  printf("to enter the same sequence.");
  printf(" When you do, you must put spaces between the digits. ");
  printf(" Good Luck! Press Enter to play ");
  scanf("%c", &another_game);

  /* One outer loop iteration is one game */
  do
  {
    correct = true;           /* By default indicates correct sequence entered  */
    counter = 0;              /* Initialize count of number of successful tries */     sequence_length = 2;      /* Initial length of a digit sequence             */
    /* Other code to initialize the game */

    /* Inner loop continues as long as sequences are entered correctly */
    while(correct)
    {
      /* On every third successful try, increase the sequence length  */       sequence_length += counter++%3 == 0;
      /* Set seed to be the number of seconds since Jan 1,1970        */       seed = time(NULL);
      /* Generate a sequence of numbers and display the number        */       srand((unsigned int)seed);    /* Initialize the random sequence */       for(int i = 1; i <= sequence_length; i++)         printf("%d ", rand() % 10); /* Output a random digit */
      /* Wait one second */
      /* Now overwrite the digit sequence */
      /* Prompt for the input sequence */
      /* Check the input sequence of digits against the original  */       srand((unsigned int)seed);      /* Restart the random sequence  */       for(int i = 1; i <= sequence_length; i++)       {         scanf("%d", &number);         /* Read an input number         */         if(number != rand() % 10)     /* Compare against random digit */         {           correct = false;            /* Incorrect entry              */           break;                      /* No need to check further...  */         }       }       printf("%s ", correct ? "Correct!" : "Wrong!");     }

    /* Output the score when the game is finished */

    /* Check if new game required*/
    printf(" Do you want to play again (y/n)? ");
    scanf("%c", &another_game);
  } while(toupper(another_game) == 'Y'),
  return 0;
}

You've declared five new variables that you need to implement the while loop that will continue to execute as long as the player is successful. Each iteration of this loop displays a sequence that the player must repeat. The counter variable records the number of times that the player is successful, and sequence_length records the current length of a sequence of digits. Although you initialize these variables when you declare them, you must also initialize their values in the do-while loop to ensure that the initial conditions are set for every game. You declare a variable, seed, of type long, that you'll pass as an argument to srand() to initialize the random number sequence returned by the function rand(). The value for seed is obtained in the while loop by calling the standard library function time().

At the beginning of the while loop, you can see that you increase the value stored in sequence_length by adding the value of the expression counter++%3 == 0 to it. This expression will be 1 when the value of counter is a multiple of 3, and 0 otherwise. This will increment the sequence length by 1 after every third successful try. The expression also increments the value in counter by 1 after the expression has been evaluated.

There are some other things to notice about the code. The first is the conversion of seed from type time_t to type unsigned int when you pass it to the srand() function. This is because srand() requires that you use type unsigned int, but the time() function returns a value of type time_t. Because the number of seconds since January 1, 1970, is in excess of 800,000,000, you need a 4-byte variable to store it. Second, you obtain a digit between 0 and 9 by taking the remainder when you divide the random integer returned by rand() by 10. This isn't the best way of obtaining random digits in the range 0 to 9, but it's a very easy way and is adequate for our purposes. Although numbers generated by srand() are randomly distributed, the low order decimal digit for the numbers in the sequence are not necessarily random. To get random digits we should be dividing the whole range of values produced by srand() into ten segments and associating one of the digits 0 to 9 with each segment. The digit corresponding to a given pseudo-random number can then be selected based on the segment in which the number lies.

The sequence of digits is displayed by the for loop. The loop just outputs the low-order decimal digit of the value returned by rand(). You then have some comments indicating the other code that you still have to add that will delay the program for one second and then erase the sequence from the screen. This is followed by the code to check the sequence that was entered by the player. This reinitializes the random number-generating process by calling srand() with the same seed value that was used at the outset. Each digit entered is compared with the low-order digit of the value returned by the function rand(). If there's a discrepancy, correct is set to false so the while loop will end.

Of course, if you try to run this code as it is, the sequence won't be erased, so it isn't usable yet. The next step is to add the code to complete the while loop.

Step 4

You must now erase the sequence, after a delay of one second. How can you get the program to wait? One way is to use another standard library function. The library function clock() returns the time since the program started, in units of clock ticks. The <time.h> header file defines a symbol CLOCKS_PER_SEC that's the number of clock ticks in one second. All you have to do is wait until the value returned by the function clock() has increased by CLOCKS_PER_SEC, whereupon one second will have passed. You can do this by storing the value returned by the function clock() and then checking, in a loop, when the value returned by clock() is CLOCKS_PER_SEC more than the value that you saved. With a variable now to store the current time, the code for the loop would be as follows:

for( ;clock() - now < CLOCKS_PER_SEC; );         /* Wait one second */

You also need to decide how you can erase the sequence of computer-generated digits. This is actually quite easy. You can move to the beginning of the line by outputting the escape character ' ', which is a carriage return. All you then need to do is output a sufficient number of spaces to overwrite the sequence of digits. Let's fill out the code you need in the while loop:

/* Program 4.12 Simple Simon */
#include <stdio.h>                     /* For input and output   */
#include <ctype.h>                     /* For toupper() function */
#include <stdbool.h>                   /* For bool, true, false  */
#include <stdlib.h>                    /* For rand() and srand() */
#include <time.h>                      /* For time() and clock() */

int main(void)
{
  /* Records if another game is to be played */
  char another_game = 'Y';

  /* true if correct sequence entered, false otherwise */
  int correct = true;

  /* Number of sequences entered successfully       */
  int counter = 0;

  int sequence_length = 0;       /* Number of digits in a sequence        */
  time_t seed = 0;               /* Seed value for random number sequence */
  int number = 0;                /* Stores an input digit                 */
  /* Stores current time - seed for random values */   time_t now = 0;   /* Rest of the declarations for the program */

  /* Describe how the game is played */
  printf(" To play Simple Simon, ");
  printf("watch the screen for a sequence of digits.");
  printf(" Watch carefully, as the digits are only displayed"
                                                " for a second! ");
  printf(" The computer will remove them, and then prompt you ");
  printf("to enter the same sequence.");
  printf(" When you do, you must put spaces between the digits. ");
  printf(" Good Luck! Press Enter to play ");
  scanf("%c", &another_game);

  /* One outer loop iteration is one game */
  do
  {
    correct = true;           /* By default indicates correct sequence entered  */
    counter = 0;              /* Initialize count of number of successful tries */     sequence_length = 2;      /* Initial length of a digit sequence             */
    /* Other code to initialize the game */

    /* Inner loop continues as long as sequences are entered correctly */
    while(correct)
    {
      /* On every third successful try, increase the sequence length */
      sequence_length += counter++%3 == 0;

      /* Set seed to be the number of seconds since Jan 1,1970       */
      seed = time(NULL);

      now = clock();         /* record start time for sequence */
      /* Generate a sequence of numbers and display the number */
      srand((unsigned int)seed);      /* Initialize the random sequence */
      for(int i = 1; i <= sequence_length; i++)
        printf("%d ", rand() % 10);   /* Output a random digit          */

      /* Wait one second */       for( ;clock() - now < CLOCKS_PER_SEC; );
      /* Now overwrite the digit sequence */       printf(" ");          /* go to beginning of the line */       for(int i = 1; i <= sequence_length; i++)         printf("  ");        /* Output two spaces           */
      if(counter == 1)       /* Only output message for the first try */         printf(" Now you enter the sequence  - don't forget"                                                " the spaces ");       else         printf(" ");        /* Back to the beginning of the line     */
/* Check the input sequence of digits against the original  */
      srand((unsigned int)seed);      /* Restart the random sequence  */
      for(int i = 1; i <= sequence_length; i++)
      {
        scanf("%d", &number);         /* Read an input number         */
        if(number != rand() % 10)     /* Compare against random digit */
        {
          correct = false;            /* Incorrect entry              */
          break;                      /* No need to check further...  */
        }
      }
      printf("%s ", correct ? "Correct!" : "Wrong!");
    }

    /* Output the score when the game is finished */

    /* Check if new game required*/
    printf(" Do you want to play again (y/n)? ");
    scanf("%c", &another_game);
  } while(toupper(another_game) == 'Y'),
  return 0;
}

You record the time returned by clock() before you output the sequence. The for loop that's executed when the sequence has been displayed continues until the value returned by clock() exceeds the time recorded in now by CLOCKS_PER_SEC, which of course will be one second.

Because you haven't written a newline character to the screen at any point when you displayed the sequence, you're still on the same line when you complete the output of the sequence. You can move the cursor back to the start of the line by executing a carriage return without a linefeed, and outputting " " does just that. You then output two spaces for each digit that was displayed, thus overwriting each of them with blanks. Immediately following that, you have a prompt for the player to enter the sequence that was displayed. You output this message only the first time around; otherwise it gets rather tedious. On the second and subsequent tries, you just back up to the beginning of the now blank line, ready for the user's input.

Step 5

All that remains is to generate a score to display, once the player has gotten a sequence wrong. You'll use the number of sequences completed and the number of seconds it took to complete them to calculate this score. You can arbitrarily assign 100 points to each digit correctly entered and divide this by the number of seconds the game took. This means the faster the player is, the higher the score, and the more sequences the player enters correctly, the higher the score.

Actually, there's also one more problem with this program that you need to address. If one of the numbers typed by the player is wrong, the loop exits and the player is asked if he wants to play again. However, if the digit in error isn't the last digit, you could end up with the next digit entered as the answer to the question "Do you want to play again (y/n)?" because these digits will still be in the keyboard buffer. What you need to do is remove any information that's still in the keyboard buffer. So there are two problems: first, how to address the keyboard buffer, and second, how to clean out the buffer.


Note The keyboard buffer is memory that's used to store input from the keyboard. The scanf() function looks in the keyboard buffer for input rather than getting it directly from the keyboard itself.


With standard input and output—that is, from the keyboard and to the screen—there are actually two buffers: one for input and one for output. The standard input and output streams are called stdin and stdout respectively. So to identify the input buffer for the keyboard you just use the name stdin. Now that you know how to identify the buffer, how do you remove the information in it? Well, there's a standard library function, fflush(), for clearing out buffers. Although this function tends to be used for files, which I'll cover later in the book, it will actually work for any buffer at all. You simply tell the function which stream buffer you want cleared out by passing the name of the stream as the argument. So to clean out the contents of the input buffer, you simply use this statement:

fflush(stdin);                         /* Flush the stdin buffer */

Here's the complete program, which includes calculating the scores and flushing the input buffer:

/* Program 4.12 Simple Simon */
#include <stdio.h>                     /* For input and output   */
#include <ctype.h>                     /* For toupper() function */
#include <stdbool.h>                   /* For bool, true, false  */
#include <stdlib.h>                    /* For rand() and srand() */
#include <time.h>                      /* For time() and clock() */

int main(void)
{
  /* Records if another game is to be played */
  char another_game = 'Y';

  /* true if correct sequence entered, false otherwise */
  int correct = false;

  /* Number of sequences entered successfully          */
  int counter = 0;

  int sequence_length = 0;     /* Number of digits in a sequence        */
  time_t seed = 0;             /* Seed value for random number sequence */
  int number = 0;              /* Stores an input digit                 */

  time_t now = 0;            /* Stores current time - seed for random values  */   int time_taken = 0;        /* Time taken for game in seconds                */
  /* Describe how the game is played */
  printf(" To play Simple Simon, ");
  printf("watch the screen for a sequence of digits.");
  printf(" Watch carefully, as the digits are only displayed"
                                                " for a second! ");
  printf(" The computer will remove them, and then prompt you ");
  printf("to enter the same sequence.");
  printf(" When you do, you must put spaces between the digits. ");
  printf(" Good Luck! Press Enter to play ");
  scanf("%c", &another_game);
/* One outer loop iteration is one game */
  do
  {
    correct = true;         /* By default indicates correct sequence entered */
    counter = 0;            /* Initialize count of number of successful tries*/
    sequence_length = 2;    /* Initial length of a digit sequence            */
    time_taken = clock();  /* Record current time at start of game       */
    /* Inner loop continues as long as sequences are entered correctly */
    while(correct)
    {
      /* On every third successful try, increase the sequence length */
      sequence_length += counter++%3 == 0;

      /* Set seed to be the number of seconds since Jan 1,1970  */
      seed = time(NULL);

      now = clock();                  /* record start time for sequence  */

      /* Generate a sequence of numbers and display the number */
      srand((unsigned int)seed);       /* Initialize the random sequence */
      for(int i = 1; i <= sequence_length; i++)
        printf("%d ", rand() % 10);    /* Output a random digit          */

      /* Wait one second */
      for( ;clock() - now < CLOCKS_PER_SEC; );

      /* Now overwrite the digit sequence */
      printf(" ");                   /* go to beginning of the line */
      for(int i = 1; i <= sequence_length; i++)
        printf("  ");                 /* Output two spaces */

      if(counter == 1)           /* Only output message for the first try */
        printf(" Now you enter the sequence  - don't forget"
                                               " the spaces ");
      else
        printf(" ");                /* Back to the beginning of the line */

      /* Check the input sequence of digits against the original */
      srand((unsigned int)seed);     /* Restart the random sequence    */
      for(int i = 1; i <= sequence_length; i++)
      {
        scanf("%d", &number);         /* Read an input number         */
        if(number != rand() % 10)     /* Compare against random digit */
        {
          correct = false;            /* Incorrect entry             */
          break;                      /* No need to check further... */
        }
      }
      printf("%s ", correct? "Correct!" : "Wrong!");
    }
    /* Calculate total time to play the game in seconds)*/     time_taken = (clock() - time_taken) / CLOCKS_PER_SEC;
    /* Output the game score */     printf(" Your score is %d", --counter * 100 / time_taken);
    fflush(stdin);
    /* Check if new game required*/
    printf(" Do you want to play again (y/n)? ");
    scanf("%c", &another_game);

  } while(toupper(another_game) == 'Y'),
  return 0;
}

The declaration required for the function fflush() is in the <stdio.h> header file for which you already have an #include directive. Now you just need to see what happens when you actually play:


To play Simple Simon, watch the screen for a sequence of digits.
Watch carefully, as the digits are only displayed for a second!
The computer will remove them, and then prompt you to enter the same sequence.
When you do, you must put spaces between the digits.

Good Luck!
Press Enter to play


Now you enter the sequence  - don't forget the spaces
2 1 4
Correct!
8 7 1
Correct!
4 1 6
Correct!
7 9 6 6
Correct!
7 5 4 6
Wrong!


 Your score is 16
Do you want to play again (y/n)? n

Summary

In this chapter, I covered all you need to know about repeating actions using loops. With the powerful set of programming tools you've learned up to now, you should be able to create quite complex programs of your own. You have three different loops you can use to repeatedly execute a block of statements:

  • The for loop, which you typically use for counting loops where the value of a control variable is incremented or decremented by a given amount on each iteration until some final value is reached.
  • The while loop, which you use when the loop continues as long as a given condition is true. If the loop condition is false at the outset, the loop block will not be executed at all.
  • The do-while loop, which works like the while loop except that the loop condition is checked at the end of the loop block. Consequently the loop block is always executed at least once.

In keeping with this chapter topic, I'll now reiterate some of the rules and recommendations I've presented in the book so far:

  • Before you start programming, work out the logic of the process and computations you want to perform, and write it down—preferably in the form of a flow chart. Try to think of lateral approaches to a problem; there may be a better way than the obvious approach.
  • Understand operator precedence in order to get complex expressions right. Whenever you are not sure about operator precedence, use parentheses to ensure expressions do what you want. Use parentheses to make complex expressions more readily understood.
  • Comment your programs to explain all aspects of their operation and use. Assume the comments are for the benefit of someone else reading your program with a view to extend or modify it. Explain the purpose of each variable as you declare it.
  • Program with readability foremost in your mind.
  • In complicated logical expressions, avoid using the operator ! as much as you can.
  • Use indentation to visually indicate the structure of your program.

Prepared with this advice, you can now move on to the next chapter—after you've completed all the exercises, of course!

Exercises

The following exercises enable you to try out what you've learned in this chapter. If you get stuck, look back over the chapter for help. If you're still stuck, you can download the solutions from the Source Code/Downloads section of the Apress web site (http://www.apress.com), but that really should be a last resort.

Exercise 4-1. Write a program that will generate a multiplication table of a size entered by the user. A table of size 4, for instance, would have four rows and four columns. The rows and columns would be labeled from 1 to 4. Each cell in the table will contain the product of the corresponding row and column numbers, so the value in the position corresponding to the third row and the fourth column would contain 12.

Exercise 4-2. Write a program that will output the printable characters for character code values from 0 to 127. Output each character code along with its symbol with two characters to a line. Make sure the columns are aligned. (Hint: You can use the isgraph() function that's declared in ctype.h to determine when a character is printable.)

Exercise 4-3. Extend the previous program to output the appropriate name, such as "newline," "space," "tab," and so on, for each whitespace character.

Exercise 4-4. Use nested loops to output a box bounded by asterisks as in Program 4.2, but with a width and height that's entered by the user. For example, a box ten characters wide and seven characters high would display as follows:

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

*    *

*    *

*    *

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

Exercise 4-5.

Modify the guessing game implemented in Program 4.7 so that the program will continue with an option to play another game when the player fails to guess the number correctly and will allow as many games as the player requires.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.212.212