© German Gonzalez-Morris and Ivor Horton 2020
G. Gonzalez-Morris, I. HortonBeginning Chttps://doi.org/10.1007/978-1-4842-5976-4_4

4. Loops

German Gonzalez-Morris1  and Ivor Horton2
(1)
Santiago, Chile
(2)
STRATFORD UPON AVON, UK
 

In this chapter, you’ll learn how you can repeat a block of statements until some condition is met. The programming mechanism for 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
  • 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

The loop is a fundamental programming tool with the ability to compare items. A comparison of some kind is always implicit in a loop because it provides the way for the loop to end. A typical loop would repeat a block of statements a given number of times. This kind of loop maintains a count of the number of times the loop block has been executed. The count is compared with the required number of loop block iterations, and the result decides when the loop should end.

In the lottery example in Chapter 3 in Program 3.8, you could change the code to give the user exactly three guesses—in other words, you could let them 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.
../images/311070_6_En_4_Chapter/311070_6_En_4_Fig1_HTML.png
Figure 4-1.

Logic of a typical loop

More often than not, you’ll find that you want to apply the same calculation to different sets of data values; a payroll program is an obvious example. 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 is not very practical. A loop allows you to use the same program code for any number of sets of data to be entered.

Before I discuss the first type of loop, I’ll introduce two more arithmetic operators that you’ll encounter frequently: the increment operator and the decrement operator . These operators are often used with loops, which is why I’ll discuss them now. I’ll start with a brief introduction and then go straight into an example of how you can use them in a loop. Once I have explained the basics of how the loop works, I’ll return to the increment and decrement operators to explain 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 one. 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 1 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 that you can store in a variable or use as part of a more complex expression. They do not directly modify the value stored in a variable. The increment and decrement operators do modify the value of their operand. The expression --number modified the value in number by subtracting 1 from it. The expression ++number adds 1 to the value stored.

The for Loop

You typically use the for loop 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 statements that call printf(), you could write this:
for(int count = 1 ; count <= 10 ; ++count)
{
  printf("  %d", count);
}
The for loop operation is controlled by what appears between 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 block containing the statement that calls printf(). Because you have just a single statement here, you could omit the braces. Figure 4-2 shows the three control expressions that are separated by semicolons. These expressions control the operation of the loop.
../images/311070_6_En_4_Chapter/311070_6_En_4_Fig2_HTML.png
Figure 4-2.

Control expressions in a for loop

The effect of each control expression is explained in Figure 4-2, but let’s take a closer look at exactly what’s going on:
  • The first control expression, int count = 1, is executed only once, when the loop starts. In the example, this creates a variable, count, with the initial value 1. This variable is local to the loop and does not exist outside the loop. If you attempt to reference count after the loop, your code will not compile.

  • The second control expression must be a logical expression that ultimately can result in true or false. In this case, it’s the expression count <= 10, which will evaluate to true as long as count is not greater than ten. The second expression is evaluated at the beginning of each loop iteration. 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 loop will execute the printf() statement as long as count is less than or equal to ten. The loop will end when count reaches 11.

  • The third control expression, ++count in this case, is executed at the end of each loop 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 have been incremented to 11, and because the second control expression will then be false, the loop will end.

Notice the punctuation in the loop statement. The for loop control expressions between the parentheses are separated by semicolons. The two semicolons must always be present. You can omit any or all of the control expressions, but when you do, you must still include the semicolons. For example, you could declare and initialize count to 1 outside the loop:
int count = 1;
Of course this statement must precede the loop because a variable only exists and is accessible in statements that follow its declaration. 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);
}
Because you define count before the loop, it will still exist after the loop, so you could output its value. As a trivial example, you could make this into a working 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(" After the loop count has the value %d. ", count);
  return 0;
}
This program will list the numbers from 1 to 10 on the first line followed by the value of count after the loop on the second line:
  1  2  3  4  5  6  7  8  9  10
After the loop count has the value 11.
The flow chart in Figure 4-3 illustrates the logic of this program.
../images/311070_6_En_4_Chapter/311070_6_En_4_Fig3_HTML.png
Figure 4-3.

The logic of Program 4.1

The steps with a bold outline are within the for loop. Let’s try a slightly different example.

Try it out: Drawing a Box
Suppose that you want to draw a box on the screen using asterisks. You could just use the printf() statement many times, but the typing would be exhausting. You can use a for loop to draw a box much more easily. Let’s try it:
// Program 4.2 Drawing a box
#include <stdio.h>
int main(void)
{
  printf(" **************");         // Draw the top of the box
  for(int count = 1 ; count <= 8 ; ++count)
    printf(" *            *");       // Draw the sides of the box
  printf(" ************** ");       // Draw the bottom of the box
  return 0;
}
No prizes for guessing, but the output for this program looks like this:
**************
*            *
*            *
*            *
*            *
*            *
*            *
*            *
*            *
**************

How It Works

The program itself is really very simple. The first printf() statement outputs the top of the box:
   printf(" **************");     // Draw the top of the box
The next statement is the for loop:
   for(int count = 1 ; count <= 8 ; ++count)
     printf(" *            *");   // Draw the sides of the box
This repeats the printf() statement eight times to output the sides of the box. You probably understand this, but let’s look again at how it works and pick up a bit more jargon. The loop control is the following:
for(int count = 1 ; count <= 8 ; ++count)
The operation of the loop is controlled by the three expressions that appear between the parentheses following the keyword for. The first expression is the following:
int count = 1
This creates and initializes the loop control variable , or loop counter , which in this case is an integer variable, count. You could have used other types of variables for this, but integers are the most suitable here. The next loop control expression is
count <= 8
This is the continuation condition for the loop. This is checked before each loop iteration to see whether the loop should continue. If the expression is true, the loop continues. When it’s false, the loop ends, and execution continues with the statement following the loop. In this example, the loop continues as long as count is less than or equal to 8. The last expression is
++count

This increments the loop counter and is executed at the end of each loop iteration. The loop statement that outputs the sides of the box will therefore be executed eight times. After the eighth iteration, count will be incremented to 9 and the continuation condition will be false, so the loop will end.

Program execution will then continue by executing the statement that follows the loop:
   printf(" ************** ");   // Draw the bottom of the box

This outputs the bottom of the box on the screen.

General Form of the for Loop

The general pattern for the for loop is
for(starting_condition; continuation_condition ; action_per_iteration)
  loop_statement;
next_statement;

The statement to be repeated is represented by loop_statement . In general, this could equally well be a block of several statements enclosed between 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 you can put any logical or arithmetic expression 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 means that the loop_statement will not be executed at all if the continuation_condition starts out as false.

The action_per_iteration is executed at the end of each loop iteration. It 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 expressions that modify the variables by commas. At each loop iteration, loop_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 a single line.

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 ++. Assuming the variables are of type int , the following three statements all have exactly the same effect:
count = count + 1;
count += 1;
++count;

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

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 the incremented value is used in the evaluation of the expression. For example, suppose count has the value 5 and you execute this statement:
total = ++count + 6;

The variable count will be incremented to 6, and this value will be used in the evaluation of the expression on the right of the assignment. Consequently, total will be assigned the value 12, so the one statement modifies two variables, count and 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 of the operator. You can also write the operator after the variable to which it applies, and this is referred to as the postfix form. The effect of the postfix form of the increment operator is significantly different from the prefix form when it’s used in an expression. If you write count++ in an expression, the incrementing of count occurs after its value has been used. This sounds more complicated than it really 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, suppose a is 10 and b is 5 in the following statement:
x = a++ + b;

x will be assigned 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, suppose you execute the following statement, with the same initial values for a and b:
y = a + (++b);

y will be assigned 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.

It works similarly to the increment operator in an expression. For example, suppose count has the value 10 in the following statement:
total = --count + 6;

The variable total will be assigned the value 15 (from 9 + 6). The variable count, with the initial value of 10, has 1 subtracted from it before it is used in the expression so that its value will be 9.

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, suppose count has the value 5 in this statement:
total = --count + 6;
total will be assigned the value 10 (from 4 + 6). In this statement
total = 6 + count-- ;

total will be assigned the value 11 (from 6 + 5).

Both the increment and decrement operators can only be applied to integer types, but this does include integer types that store character codes.

The for Loop Revisited

Now that you understand a bit more about the ++ and -- operators, let’s look at another example that uses a loop.

Try it out: Summing Numbers
This is a more useful and interesting program than drawing a box with asterisks (unless what you really need is a box drawn with asterisks). I’m sure that you have always wanted to know what all the house numbers on your street totaled. It’s such a wonderful ice-breaker at parties. Here you’re going to find out by creating a program that reads in the highest house number and then uses a for loop to sum all the numbers from 1 to the value that was entered:
//  Program 4.3 Sum the integers from 1 to a user-specified number
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
  unsigned  long long sum = 0LL;            // Stores the sum of the integers
  unsigned 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(" %u", &count);
  // Sum integers from 1 to count
  for(unsigned int i = 1 ; i <= count ; ++i)
    sum += i;
  printf(" Total of the first %u numbers is %llu ", count, sum);
  return 0;
}
The typical output you should get from this program is the following:
Enter the number of integers you want to sum: 10
Total of the first 10 integers is 55

How It Works

You start by declaring and initializing two variables that you’ll need during the calculation:
  unsigned  long long sum = 0LL;            // Stores the sum of the integers
  unsigned int count = 0;                   // The number of integers to be summed

You use sum to hold the final result of your calculations. You declare it as type unsigned long long to allow the maximum total you can deal with to be as large an integer as possible. The variable count stores the integer that’s entered as the number of integers to be summed, and you’ll use this value to control the number of iterations in the for loop.

You deal with the input by means of the following statements:
  printf(" Enter the number of integers you want to sum: ");
  scanf(" %u", &count);

After the prompt, you read in the integer that will define the sum required. If the user enters 4, for instance, the program will compute the sum of 1, 2, 3, and 4.

The sum is calculated in the following loop:
  for(unsigned int i = 1 ; i <= count ; ++i)
    sum += i;

The loop variable i is declared and initialized to 1 by the starting condition in the for loop. On each iteration, the value of i is added to sum. Because i is incremented on each iteration, the values 1, 2, 3, and so on, up to the value stored in count, will be added to sum. The loop ends when the value of i exceeds the value of count.

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.

Try it out: The Flexible For Loop
This example demonstrates how you can carry out a calculation within the third control expression in a for loop:
// Program 4.4 Summing integers - compact version
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
  unsigned  long long sum = 0LL;            // Stores the sum of the integers
  unsigned 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(" %u", &count);
  // Sum integers from 1 to count
  for(unsigned int i = 1 ; i <= count ; sum += i++);
  printf(" Total of the first %u numbers is %llu ", count, sum);
  return 0;
}
Typical output would be the following:
Enter the number of integers you want to sum: 6789
Total of the first 6789 numbers is 23048655

How It Works

This program will execute exactly the same as the previous program. The only difference is that you’ve placed the operation that accumulates the sum in the third control expression for the loop:
  for(unsigned int i = 1 ; i<= count ; sum += i++);

The loop statement is empty: it’s just the semicolon after the closing parenthesis. This expression adds the value of i to sum and then increments i for the next iteration. It works this way because you’ve used the postfix form of the increment operator. If you use the prefix form here, you’ll get the wrong answer because count+1 will be added to sum on the last iteration of the loop, instead of just count.

Modifying the for Loop Control Variable

Of course, you are not limited to incrementing the loop control variable by 1. You can change it by any amount, 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
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
  unsigned  long long sum = 0LL;            // Stores the sum of the integers
  unsigned 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(" %u", &count);
  // Sum integers from count to 1
  for(unsigned int i = count ; i >= 1 ; sum += i--);
  printf(" Total of the first %u numbers is %llu ", 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 to sum, down to 1. Again, if you used the prefix form, the answer would be wrong, because you would start by adding count-1 instead of 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 tidy little formula $$ frac{1}{2}nleft(n+1
ight) $$ for the sum of the integers from 1 to n will do the trick much more efficiently (just as Gauss did being a kid). 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. The minimal for loop looks like this:
for( ;; )
{
  /* statements */
}

The loop body could be a single statement, but when there are no loop parameters, it is usually a block of statements. Because the condition for continuing the loop is absent, the loop will continue indefinitely. Unless you want your computer to be indefinitely doing nothing, the loop body must contain the means of exiting from the loop. To stop the loop, the loop body must contain two things: a test of some kind to determine when 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 that follows 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 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 potentially execute indefinitely. The scanf() function 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.

Try it out: A Minimal For Loop
This example computes the average of an arbitrary number of values:
// Program 4.6 The almost indefinite loop - computing an average
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>                   // For tolower() function
int main(void)
{
  char answer = 'N';                 // Decision to continue the loop
  double total = 0.0;                // Total of values entered
  double value = 0.0;                // Value entered
  unsigned int count = 0;            // Number of values entered
  printf(" This program calculates the average of"
                                      " any number of values.");
  for( ;; )                           // Indefinite loop
  {
    printf(" Enter a value: ");      // Prompt for the next value
    scanf(" %lf", &value);            // Read the next value
    total += value;                   // Add value to total
    ++count;                          // Increment count of values
    // check for more input
    printf("Do you want to enter another value? (Y or N): ");
    scanf(" %c", &answer);            // Read response Y or N
    if(tolower(answer) == 'n')        // look for any sign of no
      break;                          // Exit from the loop
  }
  // Output the average to 2 decimal places
  printf(" The average is %.2lf ", total/count);
  return 0;
}
Typical output from this program is the following:
This program calculates the average of any number of values.
Enter a value: 2.5
Do you want to enter another value? (Y or N): y
Enter a value: 3.5
Do you want to enter another value? (Y or N): y
Enter a value: 6
Do you want to enter another value? (Y or N): n
The average is 4.00

How It Works

The general logic of the program is illustrated in Figure 4-4.
../images/311070_6_En_4_Chapter/311070_6_En_4_Fig4_HTML.png
Figure 4-4.

Basic logic of the program

You’ve set up the loop to continue indefinitely because the for loop has no end condition specified—or indeed any loop control expressions:
  for( ;; )                           // Indefinite loop

Therefore, so far as the loop control is concerned, the block of statements enclosed between the braces will be repeated indefinitely.

You display a prompt and read an input value in the loop with these statements:
    printf(" Enter a value: ");      // Prompt for the next value
    scanf(" %lf", &value);            // Read the next value
Next, you add the value entered to your variable total and increment count:
    total += value;                   // Add value to total
    ++count;                          // Increment count of values
Having read a value and added it to the total, you check with the user to see if more input is to be entered:
    // check for more input
    printf("Do you want to enter another value? (Y or N): ");
    scanf(" %c", &answer);            // Read response Y or N
This prompts for either Y or N to be entered. The character entered is checked in the if statement:
    if(tolower(answer) == 'n')        // look for any sign of no
      break;                          // Exit from the loop
The character stored in answer is converted to lowercase by the tolower() function that’s declared in the ctype.h header file, so you only need to test for n. If you enter N, or n, to indicate that you’ve finished entering data, the break statement will be executed. Executing break within a loop has the effect of immediately ending the loop, so execution continues with the statement following the closing brace for the loop block. This is the statement:
  printf(" The average is %.2lf ", total/count);

This statement calculates the average of the values entered by dividing the value in total by the count of the number of values. The result is then displayed.

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.

Try it out: A Guessing Game
With this program, the user has to guess a number that the program has picked as the lucky number. It uses one for loop and plenty of if statements. I’ve also thrown in a conditional operator, just to make sure you haven’t forgotten how to use it!
// Program 4.7 A Guessing Game
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
  int chosen = 15;                    // The lucky number
  int guess = 0;                      // Stores a guess
  int count = 3;                      // The maximum number of tries
  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(" Congratulations. You guessed it! ");
      return 0;                       // End the program
    }
    else if(guess < 1 || guess > 20)      // Check for an invalid guess
      printf("I said the number is between 1 and 20. ");
    else
      printf("Sorry, %d is wrong. My number is %s than that. ",
                            guess, chosen > guess ? "greater" : "less");
  }
  printf(" You have had three tries and failed. The number was %d ",
                                                                  chosen);
  return 0;
}
Some sample output would be the following:
This is a guessing game.
I have chosen a number between 1 and 20 which you must guess.
You have 3 tries left.
Enter a guess: 11
Sorry, 11 is wrong. My number is greater than that.
You have 2 tries left.
Enter a guess: 15
Congratulations. You guessed it!

How It Works

You first declare and initialize three variables of type intchosen, guess, and count:
  int chosen = 15;                    // The lucky number
  int guess = 0;                      // Stores a guess
  int count = 3;                      // The maximum number of tries

These store the number that’s to be guessed, the user’s guess, and the number of guesses the user is permitted, respectively.

You provide the user with an initial explanation of the program:
  printf(" This is a guessing game.");
  printf(" I have chosen a number between 1 and 20"
                                        " which you must guess. ");
The number of guesses that can be entered is controlled by this loop:
for( ; count > 0 ; --count)
  {
    ...
  }

All the operational details of the game are within this loop, which will continue as long as count is positive, so the loop will repeat count times.

There’s a prompt for a guess to be entered, and the guess itself is read by these statements:
    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

The first printf() looks a little complicated, but all it does is insert "y" after "tr" in the output when count is 1 and "ies" in all other cases. It’s important to get your plurals right.

After reading a guess value using scanf(), you check whether it’s correct with these statements:
    if(guess == chosen)
    {
      printf(" Congratulations. You guessed it! ");
      return 0;                       // End the program
    }

If the guess is correct, you display a suitable message and execute the return statement. This ends the function main(), so the program ends. You’ll learn more about the return statement when I discuss functions in greater detail in Chapter 8.

The program will reach the subsequent checks in the loop if the guess is incorrect:
    else if(guess < 1 || guess > 20)      // Check for an invalid guess
      printf("I said the number is between 1 and 20. ");
    else
      printf("Sorry, %d is wrong. My number is %s than that. ",
                            guess, chosen > guess ? "greater" : "less");

This group of statements first tests whether the value entered is within the prescribed limits. If it isn’t, a message is displayed reiterating the limits. If it’s a valid guess, a message is displayed to the effect that it’s incorrect, and that gives a clue as to where the correct answer is.

The loop ends after three iterations and thus three guesses. The statement after the loop is the following:
  printf(" You have had three tries and failed. The number was %d ",
                                                                  chosen);

This will be executed only if all three guesses were wrong. It displays an appropriate message, revealing the number to be guessed, and then the program ends.

The program is designed so that you can easily change the value of the variable chosen and have endless fun. Well, endless fun for a short while, anyway.

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 zero 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, stdlib.h 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.

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. (This is called an epoch that is commonly a representation of time in a 32-bit integer that starts counting from the mentioned date above. It is a de facto standard because it is not defined in the standard and follows POSIX specification.) Be aware these are seconds since 1970; so if you are trying to execute the same program at the same time, it will be necessary to handle micro- or nanoseconds in the seed. Otherwise, the sequence of pseudo-random numbers will be repeated (or use a different seed like PID), and because time always marches on, you get a different value returned by the time() function each time the program executes. The time() function requires an argument to be specified, which you’ll specify here as NULL. NULL is a symbol that’s defined in stdlib.h that represents a memory address that doesn’t refer to anything. I’ll discuss the use and significance of NULL further in 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
You only need to call srand() once in a program to initialize the sequence. Each time you call rand() subsequently, you’ll get another pseudo-random number. 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 you want. Suppose you want to obtain values in a range from zero 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 – time can be casted to (unsigned int) to avoid possible overflow
int limit = 20;                   // 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
#define _CRT_SECURE_NO_WARNINGS
#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((unsigned int)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(" Congratulations. You guessed it! ");
      return 0;                       // End the program
    }
    else if(guess < 1 || guess > 20)      // Check for an invalid guess
      printf("I said the number is between 1 and 20. ");
    else
      printf("Sorry, %d is wrong. My number is %s than that. ",
                            guess, chosen > guess ? "greater" : "less");
  }
   printf(" You have had three tries and failed. The number was %d ",
                                                                 chosen);
  return 0;
}

This version of the 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 1,000, 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 +…up to 1,000.

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 may never have the value 2.0. The loop will take over your computer and run indefinitely when this is the case (until you stop it; press Ctrl+C under Microsoft Windows).

Chars loop Control Variables

Float is not the only new data type that can be handled in a for loop; although there is a trick, we can use char to iterate in a for loop too. For C, char's are integers underneath. Thus, its use is straightforward.

For instance, this is an example to show the English alphabet:
//  Program 4.7b loop with char's
#include <stdio.h>
int main(void)
{
  char c;
  printf(" Printing out alphabet. ");
  for (c = 'A'; c <= 'Z'; c++)
    printf("%c ", c);
  printf(" ");
  return 0;
}
Note

Your compiler converts decimal floating-point values to binary. Even though 0.2 has no exact representation in binary, it is still possible that the previous loop may end normally. This is because the precise binary value for 0.2 depends on the algorithm used to generate it.

The while 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. I could describe this in words 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 and statement2 could each be a block of statements.

The logic of the while loop is shown in Figure 4-5.
../images/311070_6_En_4_Chapter/311070_6_En_4_Fig5_HTML.png
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 with “No, I’m not hungry,” then you don’t get to eat any sandwiches at all, and you move straight to the coffee. Clearly, if the loop condition starts out as true, the loop body must contain a mechanism for changing this if the loop is to end.

Be careful. A typical beginner error is that the expression of the while loop could be an assignment such as while (value = 1) instead of a correct comparison while (value == 1).

Using an assignment, the value always will be the number that is being set (this means true, unless we assign zero), and the while loop will become indefinite.

Try it out: Using The While Loop
The while loop looks fairly straightforward, so let’s go right into applying it in that old favorite, humming, and summing house numbers:
// Program 4.8 While programming and summing integers
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
  unsigned long sum = 0UL;        // The sum of the integers
  unsigned int i = 1;             // Indexes through the integers
  unsigned int count = 0;         // The count of integers to be summed
  // Get the count of the number of integers to sum
  printf(" Enter the number of integers you want to sum: ");
  scanf(" %u", &count);
  // Sum the integers from 1 to count
  while(i <= count)
    sum += i++;
  printf("Total of the first %u numbers is %lu ", count, sum);
  return 0;
}
Typical output from this program is the following:
Enter the number of integers you want to sum: 7
Total of the first 7 numbers is 28

How It Works

Well, really this works pretty much the same as when you used the for loop. The only aspect of this example worth discussing is the while loop:
  while(i <= count)
    sum += i++;
The loop body contains a single statement that accumulates the total in sum. This continues to be executed with i values up to and including the value stored in count. Because you have the postfix increment operator here (the ++ comes after the variable), i is incremented after its value is used to compute sum on each iteration. What the statement really means is this:
    sum += i;
    i++;

So the value of sum isn’t affected by the incremented value of i until the next loop iteration.

This example uses the increment operator as postfix. How could you change the preceding program to use the prefix form of the ++ operator? Have a try and see whether you can work it out before looking at the answer in the next section.

The obvious bit of code that will change will be the while loop:
     sum += ++i;
Try just changing this statement in Program 4.8. If you run the program now, you get the wrong answer:
Enter the number of integers you want to sum: 3
Total of the first 3 numbers is 9

This is because the ++ operator is adding 1 to the value of i before it stores the value in sum. The variable i starts at 1 and is increased to 2 on the first iteration, whereupon that value is added to sum.

To make the first loop iteration work correctly, you need to start with i as 0. This means that the first increment would set the value of i to 1, which is what you want. So you must change the definition of i to the following:
  unsigned int i = 0;
However, the program still doesn’t work properly because it continues the calculation until the value in i is greater than count, so you get one more iteration than you need. To fix this, you must change the control expression so that the loop continues while i is less than but not equal to count:
  while(i < count)

Now the program will produce the correct answer. This example should help you understand better the effects of postfixing and prefixing these operators.

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. Program 4.2 outputs a box with a fixed height and width. Suppose you wanted to generalize this example so it would output a box of any given width and height. The first step would be to define variables that specify the number of characters for the width and the height:
unsigned int width = 0;
unsigned int height = 0;
A width or height less than 3 is not acceptable because the box would have no interior. You can define a variable representing a minimum dimension value for the box:
  const unsigned int MIN_SIZE = 3;        // Minimum width and height values
You could read in the width and height next:
  printf("Enter values for the width and height (minimum of %u):", MIN_SIZE);
  scanf("%u%u", &width, &height);
In spite of the message, you would probably want to verify that the values entered are at least the minimum:
  if(width < MIN_SIZE)
  {
    printf(" Width value of %u is too small. Setting it to %u.", width, MIN_SIZE);
    width = MIN_SIZE;
  }
  if(height < MIN_SIZE)
  {
    printf(" Height value of %d is too small. Setting it to %u.", height, MIN_SIZE);
    height = MIN_SIZE;
  }
Finally, you could draw the box with the given height and width:
  // Output the top of the box with width asterisks
  for(unsigned int i = 0 ; i < width ; ++i)
    printf("*");
  // Output height-2 rows of width characters with * at each end and spaces inside
  for(unsigned int j = 0 ; j < height - 2 ; ++j)
  {
    printf(" *");                               // First asterisk
    // Next draw the spaces
    for(unsigned int i = 0 ; i < width - 2 ; ++i)
      printf(" ");
    printf("*");                                 // Last asterisk
  }
  // Output the bottom of the box
  printf(" ");                                  // Start on newline
  for(unsigned int i = 0 ; i < width ; ++i)
    printf("*");
  printf(" ");                                  // Newline at end of last line

You can assemble this into a complete example.

Try it out: Using Nested Loops
Here’s the complete program:
// Program 4.9 Output a box with given width and height
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
  const unsigned int MIN_SIZE = 3;        // Minimum width and height values
  unsigned int width = 0;
  unsigned int height = 0;
  // Read in required width and height
  printf("Enter values for the width and height (minimum of %u):", MIN_SIZE);
  scanf("%u%u", &width, &height);
  // Validate width and height values
  if(width < MIN_SIZE)
  {
    printf(" Width value of %u is too small. Setting it to %u.", width, MIN_SIZE);
    width = MIN_SIZE;
  }
  if(height < MIN_SIZE)
  {
    printf(" Height value of %u is too small. Setting it to %u.", height, MIN_SIZE);
    height = MIN_SIZE;
  }
  printf(" ");
  // Output the top of the box with width asterisks
  for(unsigned int i = 0 ; i < width ; ++i)
    printf("*");
  // Output height-2 rows of width characters with * at each end and spaces inside
  for(unsigned int j = 0 ; j < height - 2 ; ++j)
  {
    printf(" *");                               // First asterisk
    // Next draw the spaces
    for(unsigned int i = 0 ; i < width - 2 ; ++i)
      printf(" ");
    printf("*");                                 // Last asterisk
  }
  // Output the bottom of the box
  printf(" ");                                  // Start on newline
  for(unsigned int i = 0 ; i < width ; ++i)
    printf("*");
  printf(" ");                                  // Newline at end of last line
  return 0;
}
Here is some sample output:
Enter values for the width and height (minimum of 3): 24 7
************************
*                      *
*                      *
*                      *
*                      *
*                      *
************************

How It Works

The top and bottom of the box are created by simple identical loops. The number of iterations is the number of asterisks in each line. You generate the interior rows of output in a nested loop. The outer loop with the control variable j repeats height - 2 times. There are height rows in the box, so you subtract 2 for the top and bottom rows, which are created outside this loop. The inner loop with the control variable i outputs width - 2 spaces after a newline followed by an asterisk, which is written to the output. When the inner loop ends, another asterisk is written to the output to complete the line. Thus, a newline, followed by a complete execution of the inner loop, followed by another newline, occurs for every iteration of the outer loop. We can try a nested loop performing some calculations next.

Try it out: Arithmetic in a Nested Loop
This example is based on the summing integers program. Originally, you produced the sum of all the integers from 1 up to the value entered. Now for every house, you’ll produce the sum of all the numbers from the first house, 1, up to the current house. If you look at the program output, it will become clearer:
// Program 4.10 Sums of successive integer sequences
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
  unsigned long sum = 0UL;             // Stores the sum of integers
  unsigned int count = 0;              // Number of sums to be calculated
  // Prompt for, and read the input count
  printf(" Enter the number of integers you want to sum: ");
  scanf(" %u", &count);
  for(unsigned int i = 1 ; i <= count ; ++i)
  {
    sum = 0UL;                         // Initialize sum for the inner loop
    // Calculate sum of integers from 1 to i
    for(unsigned int j = 1 ; j <= i ; ++j)
      sum += j;
    printf(" %u %5lu", i, sum);      // Output sum of 1 to i
  }
  printf(" ");
  return 0;
}
You should see some output like this:
Enter the number of integers you want to sum: 5
1  1
2  3
3  6
4  10
5  15

As you can see, if you enter 5, the program calculates the sums of the integers from 1 to 1, from 1 to 2, from 1 to 3, from 1 to 4, and from 1 to 5.

How It Works

The program calculates the sum of the integers from 1 up to each value, for all values from 1 up to the value of count that you enter. The inner loop completes all its iterations for each iteration of the outer loop. Thus, the outer loop sets up the value of i that determines how many times the inner loop will repeat:
  for(unsigned int i = 1 ; i <= count ; ++i)
  {
    sum = 0UL;                         // Initialize sum for the inner loop
    // Calculate sum of integers from 1 to i
    for(unsigned int j = 1 ; j <= i ; ++j)
      sum += j;
    printf(" %u %5lu", i, sum);      // Output sum of 1 to i
  }

The outer loop starts off by initializing i to 1, and the loop is repeated for successive values of i up to count. For each iteration of the outer loop, and therefore for each value of i, sum is initialized to 0, the inner loop is executed, and the result is displayed by the printf() statement. The inner loop accumulates the sum of all the integers from 1 to the current value of i.

Each time the inner loop finishes, the printf() to output the value of sum is executed. Control then goes back to the beginning of the outer loop for the next iteration.

You use variables of unsigned integer types throughout because none of the values can be negative. It would still work with signed integer types, but using unsigned type ensures that a negative value cannot be stored and also provides for values of greater magnitude.

Look at the output again to see the action of the nested loop. The first loop simply sets sum to 0 each time around, and the inner loop accumulates all the integers from 1 to the current value of i. You could modify the nested loop to use a while loop for the inner loop and to produce output that would show what the program is doing a little more explicitly.

Try it out: Nesting a While Loop Within a For Loop
In the previous two examples, you nested a for loop inside a for loop. In this example, you’ll nest a while loop inside a for loop:
// Program 4.11 Sums of integers with a while loop nested in a for loop
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
  unsigned long sum = 1UL;         // Stores the sum of integers
  unsigned int j = 1U;             // Inner loop control variable
  unsigned int count = 0;          // Number of sums to be calculated
  // Prompt for, and read the input count
  printf(" Enter the number of integers you want to sum: ");
  scanf(" %u", &count);
  for(unsigned int i = 1 ; i <= count ; ++i)
  {
    sum = 1UL;                    // Initialize sum for the inner loop
    j=1;                          // Initialize integer to be added
    printf(" 1");
    // Calculate sum of integers from 1 to i
    while(j < i)
    {
      sum += ++j;
      printf(" + %u", j);         // Output +j - on the same line
    }
    printf(" = %lu", sum);        // Output  = sum
  }
  printf(" ");
  return 0;
}
This program produces the following output:
Enter the number of integers you want to sum: 5
1 = 1
1 + 2 = 3
1 + 2 + 3 = 6
1 + 2 + 3 + 4 = 10
1 + 2 + 3 + 4 + 5 = 15

How It Works

The differences are inside the outer loop. The outer loop control is exactly the same as before. What occurs during each iteration has been changed. The variable sum is initialized to 1 within the outer loop, because the while loop will add integers to sum starting with 2. The value to be added is stored in j, which is also initialized to 1. The first printf() in the outer loop just outputs a newline character followed by 1, the first integer in the set to be summed. The inner loop adds the integers from 2 up to the value of i. For each integer value in j that’s added to sum, the printf() in the inner loop outputs + j on the same line as the initial value, 1. Thus, the inner loop will output + 2, then + 3, and so on for as long as j is less than i. Of course, for the first iteration of the outer loop, i is 1, so the inner loop will not execute at all, because j < i (1 < 1) is false from the beginning.

When the inner loop ends, the last printf() statement is executed. This outputs an equal sign followed by the value of sum. Control then returns to the beginning of the outer loop for the next iteration.

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 ; ++j)            // 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 statement 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 ; ++j)          // 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.

As we declared in the last chapter, the goto statement is a very "dangerous" statement that will create a spaghetti code that highly probably will finish in problems; please use goto with moderation.

The do-while Loop

The third type of loop is the do-while loop. You may be wondering why you need this when you already have the for loop and the while loop. There’s a 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 and the for loop test at the beginning of the loop, so the body of the loop won’t execute at all when the condition is false at the outset. 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.

You can see how the do-while loop differs if you replace the preceding while loop with a do-while loop and leave the body of the loop 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 checked after the loop body executes.

The general representation of the do-while loop is
do
{
  /* Statements for the loop body */
}
while(expression);

If the loop body is just one statement, you can omit the braces. Notice the semicolon after the parentheses in a do-while loop. There isn’t one in the while loop. 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!
../images/311070_6_En_4_Chapter/311070_6_En_4_Fig6_HTML.png
Figure 4-6.

Operation of the do-while loop

Try it out: Using a Do-While Loop
You can try out the do-while loop with a little program that reverses the digits of a positive number:
// Program 4.12 Reversing the digits
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
  unsigned int number = 0;                 // The number to be reversed
  unsigned int rebmun = 0;                 // The reversed number
  unsigned int temp = 0;                   // Working storage
  // Read in the value to be reversed
  printf(" Enter a positive integer: ");
  scanf(" %u", &number);
  temp = number;                           // Copy to working storage
  // Reverse the number stored in temp
  do
  {
    rebmun = 10*rebmun + temp % 10;        // Add rightmost digit of temp to rebmun
    temp = temp/10;                        // and remove it from temp
  } while(temp);                           // Continue as long as temp is not 0
  printf(" The number %u reversed is  %u rebmun ehT ", number, rebmun );
  return 0;
}
The following is a sample of output from this program:
Enter a positive integer: 234567
The number 234567 reversed is 765432 rebmun ehT

How It Works

The best way to explain what’s going on here is to take you through a small example. Assume that 43 is entered by the user. After reading this value into number, the program copies the value in number to temp:
  temp = number;                           // Copy to working storage

This is necessary because the process of reversing the digits destroys the original value, and you want to output the original integer along with the reversed version.

The reversal of the digits is done in the do-while loop:
  do
  {
    rebmun = 10*rebmun + temp % 10;        // Add rightmost digit of temp to rebmun
    temp = temp/10;                        // and remove it from temp
  } while(temp);                           // Continue as long as temp is not 0

The do-while loop is most appropriate here because any positive number will have at least one digit. You get the rightmost decimal digit from the value stored in temp using the modulus operator, %, to obtain the remainder after dividing by 10. Because temp originally contains 43, temp%10 will be 3. You assign the value of the expression 10*rebmun + temp%10 to rebmun. Initially, the value of rebmun is 0, so on the first iteration, 3 is stored in rebmun.

You’ve now stored the rightmost digit of the input in rebmun so you remove this digit from temp by dividing temp by 10. Because temp contains 43, temp/10 will be 4.

At the end of the loop, the condition is checked, which is just the value of temp. Because temp contains the value 4, the condition is true and another iteration begins.

Note Remember, any nonzero integer will convert to true. The Boolean value false corresponds to zero.

This time, the value stored in rebmun will be 10 times rebmun, which is 30, plus the remainder when temp is divided by 10, which is 4, so the result is that rebmun becomes 34. You again divide temp by 10, so it will contain 0. Now temp is 0 at the end of the loop iteration, which is false, so the loop finishes and you have reversed the digits from number. You should be able to see that this works just as well with values with more decimal digits.

This form of loop is used relatively rarely, compared with the other two forms. Keep it in the back of your mind, though; when you need a loop that always executes at least once, the do-while loop delivers the goods.

The continue Statement

Sometimes a situation arises where 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 as
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:
enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
for(enum Day day = Monday; day <= Sunday ; ++day)
{
  if(day == Wednesday)
    continue;
  printf("It's not Wednesday! ");
  /* Do something useful with day */
}

I used an enumeration here to remind you that it is an integer type and you can use a variable of an enum type to control for a loop. This loop will execute with values of day from Monday to Sunday (which will correspond to 0–6 by default). When day has the value Wednesday, however, the continue statement will execute and the rest of the current iteration is skipped. The loop continues with the next iteration when day will be Thursday.

You’ll see more examples that use the continue statement 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 so far. I’ll introduce a few more standard library functions that you’re sure to find useful.

The Problem

The problem that you’re going to solve is to write a program to play a game of Simple Simon. Simple Simon is a memory test game. In this 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, the process repeats with a longer sequence of digits for you to try. The objective is to continue the process for as long as possible.

The Analysis

The logic of the program is quite straightforward. 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 program should then read the player’s pathetic attempt to enter the identical sequence of digits. If the player is lucky enough to get the sequence correct, the computer should repeat with another sequence of the same length. If the player’s luck holds out for three successive sequences of a given length, the program should continue by displaying a longer sequence for the player to try. This continues until the player’s luck runs out and they get a sequence wrong. The program will then calculate a score based on the number of successful tries and the time taken and invite the player to play again.

You could express the program logic in general terms in the flow chart shown in Figure 4-7.
../images/311070_6_En_4_Chapter/311070_6_En_4_Fig7_HTML.png
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. It’s reasonable to assume that at least one game will be played so the check for a new game is at the end of the game loop. Three successful sequence entries trigger an increase in the length of the next sequence. Entering an incorrect sequence ends the game. 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. In the context of this program, I’ll introduce some additional aspects to managing input from the keyboard. I’ll also explain how you can time operations within a program.

Step 1

You can start identifying the basic functional blocks of code, including the main loop for the game. The loop check should go at the end of the loop so the do-while loop fits the bill very nicely. The initial program code will be this:
// Program 4.13 Simple Simon
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>                  // For input and output
#include <ctype.h>                  // For toupper() function
int main(void)
{
  char another_game = 'Y';          // Records if another game is to be played
  const unsigned int DELAY = 1;     // Display period in seconds
  /* More variable 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 %u second%s ", DELAY, DELAY > 1 ? "s!" :"!");
  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);
  // Game loop - one outer loop iteration is a complete game
  do
  {
    /* Initialize a game                        */
    /* Inner loop to play the game              */
    /* Output the score when a 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;
}

The another_game variable that you define at the beginning of main() controls whether or not another game is started when the current game finishes. A character is read from the keyboard at the end of the main game loop into this variable, and its value is checked in the loop condition. If y or Y is entered, the loop continues for another game. Otherwise, the program ends. By converting another_game to uppercase, you avoid having to check for either y or Y.

The DELAY variable is a fixed integer value that specifies the number of seconds the digit sequence will be displayed before it is erased. You’ll use this to control how long the program waits before erasing a sequence of digits. It is 1 here, but you can increase this to make the game easier.

The first block of code consists of printf() function calls that output an explanation of how the game is played. Note how you automatically concatenate two strings in this printf() statement:
  printf(" Watch carefully, as the digits are only displayed"
                                " for %u second%s ", DELAY, DELAY > 1 ? "s!" :"!");

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 takes care of assembling them into a single string. This statement also uses the conditional operator to append "s!" to the output instead of "!" when DELAY is more than 1 second.

Step 2

Next, you can add a declaration for another variable with the name correct that you’ll use to record whether or not the entry from the player is correct. You’ll use this variable to control the inner loop that plays a single game:
// Program 4.13 Simple Simon
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>                  // For input and output
#include <ctype.h>                  // For toupper() function
#include <stdbool.h>              // For bool, true, false
int main(void)
{
  char another_game = 'Y';          // Records if another game is to be played
  const unsigned int DELAY = 1;     // Display period in seconds
  bool correct = true;            // true for correct sequence, false otherwise
  /* Rest of the declarations for the program */
  // statements describing how the game is played as before ...
  // Game loop - one outer loop iteration is a complete game
  do
  {
    correct = true;               // Indicates correct sequence entered
    /* Other code to initialize the game */
    // Inner loop continues as long as sequences are entered correctly
    while(correct)
    {
      /* Statements to 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. 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. The while loop continues as long as correct has the value true. You will set it to false when the player enters a sequence incorrectly.

Caution

The code will compile as it is, and you should compile it to check it out, but you should not run it yet. If you run this as it is, program execution will never end because it contains an indefinite loop—the inner while loop. The condition for this loop is always true because the loop doesn’t change the value of correct. However, you’ll be adding that bit of the program shortly.

As you develop a program, it’s a good approach to make sure that the code will at least compile at each step. If you write all the code in one attempt, you are likely to end up with larger numbers of errors to correct, and as you correct one problem, more may appear. This can be very frustrating. If you develop and check out the code incrementally, the errors will be easier to identify and development will be faster. This brings me back to our current program.

Step 3

You have a slightly trickier task next: generating the sequence of random digits. There are two problems to be solved. The first is how you generate the sequence of random digits. The second is how you check the player’s input against the computer-generated sequence.

The digits in the sequence that you generate have to be random. You’ll use the functions rand() , srand() , and time() , which you used earlier in this chapter, to do this. These require the standard library headers stdlib.h and time.h to be included in the source file. You can get a random digit by using the % operator to obtain the remainder after dividing the integer that rand() returns by 10.

You call the srand() function with a seed value produced by the time() function as the argument to initialize the sequence of values produce by rand(). By passing the value returned by time() to srand(), you ensure that the sequence produced by rand() will be different each time.

The time() function accepts the address of a variable as an argument in which the time value is to be stored, and it also returns the same value. If you store the return value, you may not want to supply the address of a variable as the argument. In this case, you specify the argument as NULL, which is an address that doesn’t refer to anything. In the game program, you will pass the address of a variable to time() in which the time value will be stored as well as make use of the value returned.

Now let’s consider how creating and checking the sequence is going to work. You’ll need a given sequence of random digits twice: first to output it for a limited time and second to check the player’s input against it. You could consider saving the sequence of digits as an integer value. 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 the digits in integer values of type unsigned long long. Ideally the program should allow sequences to be of unlimited length. There is a simple approach you can adopt that will allow this.

The sequence of integers that the rand() function produces is determined by the seed value. Each time you pass a given seed value to srand() , rand() will return the same sequence of integers. If you store the seed value you use when you call srand() to initialize the sequence that you output, you can use this a second time to reinitialize the sequence when you are checking the user’s input. Calls to rand() will then generate the same sequence again.

You can add code to the program to generate the sequence of random digits and check them against what the player enters:
// Program 4.13 Simple Simon
#define _CRT_SECURE_NO_WARNINGS
#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)
{
  char another_game = 'Y';          // Records if another game is to be played
  const unsigned int DELAY = 1;     // Display period in seconds
  bool correct = true;              // true for correct sequence, false otherwise
  unsigned int tries = 0;         // Number of successful entries for sequence length
  unsigned int digits = 0;        // Number of digits in a sequence
  time_t seed = 0;                // Seed value for random number sequence
  unsigned int number = 0;        // Stores an input digit
  /* Rest of the declarations for the program */
  // statements describing how the game is played as before ...
  // Game loop - one outer loop iteration is a complete game
  do
  {
    // Initialize game
    correct = true;                 // Indicates correct sequence entered
    tries = 0;                    // Initialize count of successful tries
    digits = 2;                   // Initial length of digit sequence
    /* Other code to initialize the game      */
    // Inner loop continues as long as sequences are entered correctly
    while(correct)
    {
      ++tries;                         // A new attempt
      // Generate a sequence of digits and display them
      srand((unsigned int)time(&seed));              // Initialize the random sequence
      for(unsigned int i = 1 ; i <= digits ; ++i)
        printf("%d ", rand() % 10);    // Output a random digit
      /* Code to wait one second              */
      /* Code to overwrite the digit sequence */
      /* Code to prompt for the input sequence */
      srand((unsigned int)seed);                    // Reinitialize the random sequence
      for(unsigned int i = 1; i <= digits; ++i)
      // Read the input sequence & check against the original
      {
        scanf("%u", &number);         // Read a digit
        if(number != rand() % 10)     // Compare with generated digit
        {
          correct = false;            // Incorrect entry
          break;                      // No need to check further...
        }
      }
      // On every third successful try, increase the sequence length
      if(correct && ((tries % 3) == 0))
        ++digits;
      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 four new variables that you need to implement the inner while loop that continues to execute as long as the player is successful. Each loop iteration displays a sequence of digits that the player must memorize and enter when it is no longer shown: tries records the number of times that the player is successful, and digits records the current length of the sequence of digits. Although you initialize these variables when you declare them, you must also initialize them in the do-while loop before the nested while loop to ensure that the correct initial conditions are set for each game. You declare a variable, seed, of type time_t, that you use to record the value produced by the time() function. You’ll use this to initialize the random number sequence returned by the function rand(). The value for seed is set in the while loop by passing its address to the standard library function time(). The same seed value is returned by the time() function, and you use this as the argument to the first call of srand() to initialize the random sequence from which you obtain the digits for display.

At the beginning of the while loop , you increase the value stored in tries because a new attempt occurs on each loop iteration. At the end of the loop, you increment digits each time three correct attempts have been entered.

You obtain a digit between 0 and 9 by taking the remainder after dividing the random integer returned by rand() by 10. This isn’t the best method for obtaining random digits, but it’s a very easy way and is adequate for our purposes. Although the numbers that rand() generates are randomly distributed, the low-order decimal digit for numbers in the sequence is not necessarily random. To get properly random digits, you should be dividing the entire range of values produced by rand() into ten segments and associating a different decimal digit with each segment. The digit corresponding to a given pseudo-random number is then 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 1 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 seed value that you stored in seed. Each digit that is entered is compared with the low-order digit of the value returned by rand(). If there’s a discrepancy, the player got it wrong so you set correct to false and execute a break statement, which will cause the for loop to end. When the value of correct is false, the outer while loop will also 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 the while loop that will erase the sequence.

Step 4

You must erase the sequence after waiting DELAY seconds . How can you get the program to wait? One way is to use another standard library function. The clock() function in the time.h header returns the time since the program started, in units of clock ticks , where the duration of a clock tick depends on your processor. The time.h header file defines a symbol CLOCKS_PER_SEC that corresponds to the number of clock ticks in one second, so you can use this to convert from clock ticks to seconds. If you cause the program to wait until the value returned by clock() has increased by DELAY*CLOCKS_PER_SEC, then DELAY seconds will have passed. You can cause the program to wait by storing the value returned by the function clock() and then checking in a loop for when the value returned by clock() is DELAY*CLOCKS_PER_SEC more than the value that you saved. With a variable wait_start to store the current time, the code for the loop would be as follows:
for( ;clock() - wait_start < DELAY*CLOCKS_PER_SEC; );     // Wait DELAY seconds

This loop executes repeatedly until the condition is false, whereupon the program will continue.

You need to erase the sequence of computer-generated digits next. This is actually quite easy. You can move the command-line cursor to the beginning of the current output line by outputting the escape character ' ', which is a carriage return. You can then 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.13 Simple Simon
// include directives as before...
int main(void)
{
  // Variable definitions as before...
  time_t wait_start = 0;                    // Stores current time
  /* Rest of the declarations for the program */
  // statements describing how the game is played as before ...
  // Game loop - one outer loop iteration is a complete game
  do
  {
    correct = true;                  // Indicates correct sequence entered
    tries = 0;                       // Initialize count of successful tries
    digits = 2;                      // Initial length of digit sequence
    /* Other code to initialize the game      */
    // Inner loop continues as long as sequences are entered correctly
    while(correct)
    {
      ++tries;                        // A new attempt
      wait_start = clock();         // record start time for sequence
      // Code to generate a sequence of digits and display them as before...
      for( ; clock() - wait_start < DELAY*CLOCKS_PER_SEC ; );  // Wait DELAY seconds
      // Now overwrite the digit sequence
      printf(" ");                   // Go to beginning of the line
      for(unsigned int i = 1 ; i <= digits ; ++i)
        printf("  ");                 // Output two spaces
      if(tries == 1)                // Only output message for 1st try
        printf(" Now you enter the sequence  - don't forget"
                                               " the spaces ");
      else
        printf(" ");                // Back to the beginning of the line
      // Code to check the digits entered as before...
      // Code to update digits and display a message as before...
    }
    /* 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 that clock() returns before you output the sequence. The for loop that’s executed after the sequence has been displayed and continues until the value returned by clock() exceeds the time recorded in wait_start by DELAY*CLOCKS_PER_SEC.

Because you did not output a newline character when you displayed the sequence, the same output line is still current. You can move the cursor back to the start of the current line by executing a carriage return without a linefeed; outputting " " does just that. You then output two spaces for each digit that was displayed, thus overwriting each of them. You then output a prompt for the player to enter the sequence that was displayed. You output this message only once; otherwise, it gets rather tedious. On subsequent tries, you just back up to the beginning of the now blank line, ready for the user’s input.

Step 5

You need to generate a score at the end of a game, which will be given when the player gets a sequence wrong. Ideally the score should be a number of points that reflects the length of the longest sequence entered successfully as well as how fast the game was played. You’ll need four more variables in main() for this:
  clock_t start_time = 0;              // Game start time in clock ticks
  unsigned int score = 0;              // Game score
  unsigned int total_digits = 0;       // Total of digits entered in a game
  unsigned int game_time = 0;          // Game time in seconds
As a starting point for the score, you could arbitrarily award ten points for each digit in the longest sequence that was entered correctly:
score = 10*(digits - (tries % 3 == 1));

The digits value is the length of the current sequence. If the player failed on the first attempt at a sequence of digits length, the value in digits is 1 too many for scoring purposes. On the first try for a sequence of a given length, tries will have a value of the form 3*n+1 because three tries are necessary at each sequence length. Thus, the expression (tries % 3 == 1) will be 1 (true) when the player fails at the first try for a sequence of a given length, so the effect in the statement is to reduce the digits value by 1 when this is the case.

To work out the points scored for a faster time, you need to define a standard time for entry of a digit and find out how long the game took. You can allow 1 second as the standard time to enter a digit. You can award a further ten points for each second less than the standard that the player needed to enter all the digits in a complete game. To calculate this, you must figure out how many digits were entered. You can start by calculating the number of digits entered for the sequence length when the player failed.

If the player fails on the last attempt of the set of three for a given length, tries will be a multiple of 3. In this case, 3*digits is the number of digits entered. If tries is not a multiple of 3, then the digit count is the value of digits multiplied by the remainder after dividing tries by 3. Thus, the number of digits entered for all attempts at the current length is produced by this statement:
 total_digits = digits*((tries % 3 == 0) ? 3 : tries % 3);

You now need to work out the number of digits entered for all sequence lengths less than the current length. These sequences have lengths from 2 to digits-1, and there must have been three successful tries at each length.

The sum of the integers from 1 to n is given by the formula $$ frac{1}{2}nleft(n+1
ight) $$. You can obtain the count of all digits entered for sequences prior to the current length as three times the sum of the integers from 2 to digits-1. You can get this value by using the formula to sum the digits from 1 to digits-1 and then subtracting 1 from the result. Finally, you need to multiply by 3 because there are three tries at each length. Thus, you can increment total_digits to include this with the following if statement:
if(digits > 2)
  total_digits += 3*((digits - 1)*(digits)/2 - 1);

The value in total_digits is also the number of seconds required as standard for all the input because each digit is allowed 1 second. You must get the actual time for digit entry and compare it to this. You recorded the time when the game started in start_time as a number of clock ticks. The overall elapsed time for the game in seconds will therefore be (clock() - start_time )/CLOCKS_PER_SEC. Each sequence is displayed for DELAY seconds, so to be fair to the player, you must subtract the total delay time for all sequences. This will be tries*DELAY.

The final value of score can be calculated like this:
game_time = (clock() - start_time)/CLOCKS_PER_SEC - tries*DELAY;
if(total_digits > game_time)
  score += 10*( total_digits - game_time);

Unfortunately, the program is still not quite correct. The program starts to read and check digits after the player presses Enter at the end of a sequence. If an incorrect digit is entered and it isn’t the last in the sequence, the reading of digits stops and the remaining digits will be left in the keyboard buffer. This will result in the next digit being read as the answer to the prompt for another game. You need to remove any information that’s still in the keyboard buffer before prompting for the next game for the program to work correctly. This implies that you need a way to clear the keyboard buffer.

Note

The keyboard buffer is memory that’s used by the operating system to store input characters from the keyboard. The scanf() function reads input from the keyboard buffer rather than getting it directly from the keyboard itself.

With standard input and output—that is, input from the keyboard and output to the command line on the screen—there are two buffers: one that holds input characters and one for holding output. The operating system manages the transfer of data between these buffers and the physical devices. The standard input and output streams are identified by the names stdin and stdout, respectively.

There’s a standard library function, fflush() , for clearing out the contents of an input or an output buffer. This function is typically used for file buffers, which you’ll learn about in Chapter 12, but it works for any buffer. To clear a buffer for a given stream, you call fflush() with the name of the stream as the argument. For an input buffer, the data will be cleared. For an output buffer, the data will be written to the destination, thus emptying the buffer. To remove the contents of the keyboard buffer, you call fflush() with the name of the keyboard input stream as the argument:
fflush(stdin);                         // Flush the stdin buffer
Here’s the complete program, which includes calculating a score and flushing the input buffer:
// Program 4.13 Simple Simon
#define _CRT_SECURE_NO_WARNINGS
#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)
{
  char another_game = 'Y';             // Records if another game is to be played
  const unsigned int DELAY = 1;        // Display period in seconds
  bool correct = true;                 // true for correct sequence, false otherwise
  unsigned int tries = 0;              // Number of successful entries for sequence length
  unsigned int digits = 0;             // Number of digits in a sequence
  time_t seed = 0;                     // Seed value for random number sequence
  unsigned int number = 0;             // Stores an input digit
  time_t wait_start = 0;               // Stores current time
  clock_t start_time = 0;              // Game start time in clock ticks
  unsigned int score = 0;              // Game score
  unsigned int total_digits = 0;       // Total of digits entered in a game
  unsigned int game_time = 0;          // Game time 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 %u second%s ", DELAY, DELAY > 1 ? "s!" :"!");
  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);
  // Game loop - one outer loop iteration is a complete game
  do
  {
    // Initialize game
    correct = true;                    // Indicates correct sequence entered
    tries = 0;                         // Initialize count of successful tries
    digits = 2;                        // Initial length of digit sequence
    start_time = clock();              // Record time at start of game
    // Inner loop continues as long as sequences are entered correctly
    while(correct)
    {
      ++tries;                         // A new attempt
      wait_start = clock();            // record start time for sequence
      // Generate a sequence of digits and display them
      srand((unsigned int)time(&seed));              // Initialize the random sequence
      for(unsigned int i = 1 ; i <= digits ; ++i)
        printf("%u ", rand() % 10);    // Output a random digit
      for( ; clock() - wait_start < DELAY*CLOCKS_PER_SEC; );  // Wait DELAY seconds
      // Now overwrite the digit sequence
      printf(" ");                    // Go to beginning of the line
      for(unsigned int i = 1 ; i <= digits ; ++i)
        printf("  ");                  // Output two spaces
      if(tries == 1)                   // Only output message for 1st try
        printf(" Now you enter the sequence  - don't forget"
                                               " the spaces ");
      else
        printf(" ");                  // Back to the beginning of the line
      srand((unsigned int)seed);                     // Reinitialize the random sequence
      for(unsigned int i = 1 ; i <= digits ; ++i)
      // Read the input sequence & check against the original
      {
        scanf("%u", &number);          // Read a digit
        if(number != rand() % 10)      // Compare with generated digit
        {
          correct = false;             // Incorrect entry
          break;                       // No need to check further...
        }
      }
      // On every third successful try, increase the sequence length
      if(correct && ((tries % 3) == 0))
        ++digits;
      printf("%s ", correct ? "Correct!" : "Wrong!");
    }
    // Calculate and output the game score
    score = 10*(digits - ((tries % 3) == 1));         // Points for sequence length
    total_digits = digits*(((tries % 3) == 0) ? 3 : tries % 3);
    if(digits > 2)
      total_digits += 3*((digits - 1)*(digits)/2 - 1);
    game_time = (clock() - start_time)/CLOCKS_PER_SEC - tries*DELAY;
    if(total_digits > game_time)
      score += 10*(total_digits - game_time);         // Add points for speed
    printf(" Game time was %u seconds. Your score is %u", game_time, score);
    fflush(stdin);                                    // Clear the input buffer
    // 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 1 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
Correct!
8 7
Correct!
4 1
Correct!
7 9 6
Correct!
7 5 4
Wrong!
 Game time was 11 seconds. Your score is 30
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 on 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/Download section of the Apress website (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. Modify Program 4.13 to determine the random digits by selecting a digit based on where the number returned by rand() lies within the entire range of possible values.

Exercise 4-5. Modify the Simple Simon game implemented in Program 4.7A 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.

Exercise 4-6. Calculate number Pi by using the Leibniz Formula:

$$ 1-frac{1}{3}+frac{1}{5}-frac{1}{7}+frac{1}{9}-cdots =frac{pi }{4} $$

This formula has low convergence rate; then please use at least 500,000 iterations to have an accurate Pi approximation.

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

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