7.2. Hand and Eyeball Checks


Hand simulation

If you suspect that a function definition is wrong (which you should do if you have no good reason to believe that it is correct) then a good way to find an error is to step through the function body by hand on a simple parameter. When you hit function calls in the body, assume that they work according to their contracts. If they don't, that is not this function's fault.

Do not try to perform a hand simulation in your head. Put your hand to work. Get a piece of paper and a pencil and show the variables. Do the simulation carefully on the paper. One of the most common mistakes is to do the simulation based on what you want the function to do rather than based on what the function body actually says. Pay attention to details.

You will find that quite a few errors can be diagnosed with hand simulations, and the simulation itself usually suggests a way to fix the error. You will fix errors much more quickly this way than by trying things without the benefit of understanding where the computation goes wrong.


Boundary values

Always test unusual parameters that are at some sort of boundaries or extremes. For example, if a function takes a nonnegative integer as a parameter, what does it do when that parameter is 0? Try things that are very small. If a function compares two values, what does it do when they are equal to one another?


Sanity checks

Sanity, or common-sense, checks are easy to carry out by inspection. They just make sure that a function definition is sensible, in common sense terms, without going through the details of a hand simulation. Here are some common sanity checks.

Do functions have the correct number of arguments?

If you use a function that has 2 arguments, be sure that it is passed 2 arguments. If the function that you are defining is supposed to have 1 argument, according to its contract, make sure that it has 1 argument.

Inspect for type errors.

If a function expects an integer argument, check that you are passing it an integer. If a function returns an integer, make sure that you treat its result as an integer.

Check for returns.

If your function has a non-void return type, be sure that it returns a result no matter how the computation goes.

If your function returns a boolean result, it normally returns true sometimes and false sometimes. Check to see that both results are possible. If it only returns true, something is wrong.


Make sure that critical information is used.

A function usually needs to get some information from its arguments. Be sure that it mentions each argument. If an argument is a structure, be sure that it looks at each part of the structure that it needs in order to compute its result.

For example, suppose that function sum(L) is supposed to compute the sum of the numbers in a linked list of integers. Does it mention the item stored in a list cell? If not, then it does not look at the items at all, so it cannot possibly add them up.


Do not mix loops with recursion

In this course, we will never write a function that includes a loop and is also recursive. Check that you have not done that.

Check for repetition

If the problem that you are solving requires some kind of repetition because it needs more steps on larger arguments or inputs, then make sure that the repetition is done somewhere. The function will need to contain a loop, or it will need to be recursive, or it will need to call another function that performs repetition.

Check if vs. while

Beginners often write if where they mean while, or the other way around. Check that you have not done that.


Exercises

  1. Given the following function definition, perform a hand-simulation of f(3). Show the variables each time the loop reaches its beginning. What is returned?

      int f(int x)
      {
        int i = 0;
        int s = 1;
        while(i < x)
        {
          i = i + 1;
          s = s + s;
        }
        return s;
      }
    
    Answer

  2. Given the following function definition, perform a hand-simulation of g( ). Show the array contents each time the second loop reaches its beginning. Also show the value that i will have for the next iteration. What does g( ) print? (Note: This function contains 3 loops, which we normally do not allow, but this is for illustration.)

      void g()
      {
        int A[5];
        for(int i = 0; i < 5; i++)
        {
          A[i] = i;
        }
        for(int i = 0; i < 4; i++)
        {
          A[i+1] = A[i] - 1;
        }
        for(int i = 0; i < 5; i++)
        {
          printf("%i\n", A[i]);
        }
      }
    
    Answer

  3. The following function has an error. Do an eyeball check to find the error.

      int h(int x)
      {
        int y = x + 1;
      }
    
    Answer

  4. The following function has an error. Do an eyeball check to find the error.

      // w(x,y) returns the smallest prime number that
      // is greater than or equal to x and less than
      // or equal to y.  If there is no such prime
      // number, it returns 0.
    
      int w(int x, int y)
      {
        int i = x;
        while(!isPrime(i))
        {
          i++;
        }
        return i;
      }
    
    Answer

  5. The following function has an error. Do an eyeball check to find the error.

      // z(x,y) returns the sum of x and y.
    
      void z(int x, int y, int r)
      {
        r = x + y;
      }
    
    Answer