4.7 Avoiding Errors and Debbuging

Avoiding Errors

  1. In setting up a loop, take the time to choose an appropriate structure. If a simple counted loop is required and you know how many times the loop will be performed, use a for statement. If a conditional loop is called for, you have to choose between a while or a do. To make this decision, it is often helpful to use the following criteria.
    1. If it is easier to test the condition that controls the loop at the start, you should probably use a while but if it is easier to test at the end of the loop, use a do.
    2. If it is possible that the loop might be executed zero times, use a while but if it is certain that it will be executed at least once, a do might be more appropriate.
    3. If a loop has both counting and conditional elements, it is usually (but not always) best to use a for statement.
  2. Enter a loop appropriately. Be sure that you have correctly initialized all variables that need to be defined before you enter the loop.
  3. In a conditional loop, be sure that there is some action that ensures that the program will eventually exit from the loop.
  4. Be careful, as usual, of having semi-colons where they do not belong. As an example, consider the following fragment.
       for (int i = 1; i <= 100; i++);
          System.out.println(i + " " + i*i); 
    This will not print a table of squares of the integers from 1 to 100. The body of the f or statement contains only an empty statement (terminated by the semi-colon on the first line). The println statement is not part of the loop at all.
  5. Since while and if statements can have similar forms, it is not uncommon for beginning programmers to use the wrong one. A while statement is a type of loop; an if statement is not.
  6. If you write a for statement that starts with the header
       for (int i = 1; i <= 100; i++)  
    then anybody reading your program expects that the loop will be executed 100 times. If the loop contains a statement of the form
       if (x < 0)
          i = 101; 
    then your intentions would be much clearer and less likely to cause an error.
  7. We saw in Section 4.4 that in for statements, the expressions contained in parentheses (following the word for) can take many forms. Although there are occasions when these constructs are useful, they can be confusing and should, in general, be avoided. It is almost always better to keep things simple and clear.

Debugging

  1. If a program containing a loop compiles correctly but, when it is run, the computer appears to do nothing, then you may have written an infinite loop. Once you have stopped the program, try running it again with tracing statements in the body of the loop. If the program is caught in an infinite loop, any output in the body of the loop will fly by on the screen. To make the tracing statements readable in such circumstances, insert a statement like char junk = In.getChar(); after your tracing statement. This will give you a chance to read the output of the tracing statement each time the program executes the body of the loop.
  2. It is very easy to write a loop that performs one too many or one too few iterations. The difference between failure and success of a program could be something as simple as the difference between the expressions while (x > 0) and while (x >= 0).
  3. If a program containing a conditional loop is not performing correctly and the expression that controls the loop is a compound expression, check that all and's, or's, and not's are being used correctly.
  4. Using floating point values to control a loop can lead to problems because of roundoff errors. As an example, consider the statement
       for (double x = 0; x < 1; x += 0.1)
          System.out.println(x) ; 
    The intention here is that the loop should execute ten times, for x having the values 0.0,0.1,0.2, ... ,0.9 and should stop after that. Unfortunately, this does not occur. Java does not store floating point values in decimal form. Consequently, values that have an exact decimal form (like 0.1), are often stored as approximations by Java. When x "should" have the value 1.0 (stopping the loop), it is actually approximately equal to 0.999 999 999 999 999. Since this is less than 1.0, the loop is executed an eleventh time. The problem here could be solved by using an integer counter for the loop, as follows.
       for (int i = 0; i < 10; i++)
          System.out.println(i/10.0); 

Exercise 4.7

  1. In the section on avoiding errors, we stated that the fragment
       for (int i = 1; i < 100; i++);
          System.out.println(i + " " + i*i);  
    would not print a table of squares of the integers from 1 to 100. What would it print?
  2. What value(s) of the variable response will stop the following loops?
    1. while (response <= 'a' && response >= 'z' )...
    2. while (response >= 'A' II response <= 'E' )...
    1. What is wrong with the following fragment?
         do
         {
            System.out.println("Enter transaction code");
            char transCode = In.getChar();
            System.out.println("Code entered: " + transCode
                              + "\nls this correct? (Y/N)");
            char response = In.getChar();
         }
         while (response != 'Y' I I response != 'N'); 
    2. Modify the fragment so that it behaves in a more appropriate way.
  3. How many times will the following loop be executed? Justify your answer.
       int n = 40;
       while (n > 0);
       {
          System.out.println(n);
          n /= 2;
       } 
  4. Rewrite each loop to make it clearer.
    1. for (int i = 1; i <= 20; i++)
         if (i % 2 == 0)
            System.out.println(i + "" "" + i*i);  
    2. for (int i = 0; i <= 10; i++)
         if (i*i < 2*i + 4)
            System.out.println(i + "" "" + i*i);
         else
            i = 11;  
    3.    int i = 20;
         while (i > 0)
         {
            System.out.println(i + "" "" + i*i);
            i--;
         }