CSCI 1300 - Exercise 2
Programming Errors and the Debugger

What You'll Get from This Exercise

Last week you learned how to edit, compile and run programs using Visual C++. If Visual C++ is not installed on your machine, then you may obtain them from the instructions in www.cs.colorado.edu/~main/intro/software.html.

Now we would like you to learn about a debugger that you will use this semester.

Create a Project
As you did last week, start Visual C++ and create a new project called heatwave2. In order to use the debugger, this must be a CLR Empty Project (rather than a plain Empty Project). The steps are given here:
  1. Choose File-->New-->Project
  2. In the Project Type window, click on Visual C++. (You might have to first open the "Other Languages" option.)
  3. In the Template window, click on CLR Empty Project. (Later we will create more compilicated kinds of projects.)
  4. In the Name textbox, type the name: heatwave
  5. Please write down the path that's listed in the Location box. You'll need to know this location later when you save the files that you've created.
  6. Click the OK button.
At this point, your project has been created and Visual Studio has created some of the files that every project requires. Next, you'll create one more file that contains your first C++ program, hooray!
  1. In the Solution Explorer window, RIGHT click on Source Files, choose Add, click on New Item.
  2. In the Templates window, click on C++ File (.cpp)
  3. In the Name text box, type the name heatwave.cxx --this will be the name of your first C++ program. Most programmers use ".cpp" for the file type of a C++ program, but we like to be a bit different, so please use .cxx instead!
  4. Click the Add button.
The blank window that opened up is the spot where you would normally type your program. For this exercise, though, please highlight the following code in your browser (by clicking the left mouse button at the front of the code, dragging the mouse over the entire code block, then lifting up the mouse button. Then copy the code (Ctrl-C). Then go back to the blank window and paste in the code (Ctrl-V):
//****************************************************************************
// ABOUT THIS PROGRAM (heatwave.cxx)
//   Written by: Michael Main, January 4, 2007
//   Email address: main@colorado.edu
//   Exercise for student: Irving Forbush
//
// INPUT: The program prompts the user to enter the height and radius of
//   a tree. To make things simpler, we assume that the tree is a perfect
//   cylinder.  The height is entered first (measured in feet), and then the
//   radius is entered (also measured in feet).
//   The program then prompts the user to enter the number of cubic feet of
//   wood required to heat a house for one day.
//
// OUTPUT: The program calculates the number of days that the tree will heat
//   a house, and outputs this value.
//
// EXAMPLE DIALOG:
//   How tall is your tree in feet?
//   13.2
//   What is the radius of the tree in feet?
//   2.1
//   How many cubic feet of wood will heat a house for a day?
//   40.2
//   That tree will heat a house for 4.54921 days.
//**************************************************************************

#include <iostream>           // Provides cin, cout
#include <cstdlib>            // Provides EXIT_SUCCESS
using namespace std;

const double PI = 3.14159;    // Defined to make the program readable

int main () 
{
    double height;            // Height of a tree in feet
    double radius;            // Radius of a tree in feet
    double requirement;       // Cubic feet of wood to heat house for a day
    double volume;            // Volume of the tree in cubic feet
    double days;              // Number of days that tree will heat house

    // Prompt user for input and read responses
    cout << "How tall is your tree in feet?" << endl;
    cin >> height;
    cout << "What is the radius of the tree in feet?" << endl;
    cin >> radius;
    cout << "How many cubic feet of wood will heat a house for a day?" << endl;
    cin >> requirement;

    // Computations
    volume = height * PI * radius * radius;
    days = volume / requirement;

    // Output days
    cout << "That tree will heat a house for " << days << " days." << endl;

    return EXIT_SUCCESS;
}

After you have copied this program, please compile the project (Build-->BuildSolution) and proceed to the next step.

Setting a Breakpoint and Starting the Debugger
  • Today you'll start by running a debugger session using the heatwave program. To get the debugger started on the heatwave program:
    1. In the gray bar to the left of your code, click on the first line with a cout instruction. A red dot appears in the gray bar to indicate that you have set a "breakpoint," which is a point in your code where the debugger will stop to let you examine things.

      The program will pause every time it reaches this line of code. If you later want to remove the breakpoint, you can do so by clicking again on the red dot.

    2. Click the Debug menu and select Start Debugging.
  • Stepping Through the Program One Line at a Time (the F10 instruction)
    When the debugger starts, the bottom of the screen opens a window called the "Call Stack." We'll examine the purpose of this window later. For now, notice that there is a yellow arrow in the gray bar to the left of your code. This arrow marks the line of code that has not yet been executed, but it is just about to be executed. For our example, this is the first cout statement of the main function.

    In order to execute that one line, press the F10 key. Notice that the message has now appeared in the console output window, yay! Also, the yellow arrow moved down one line, so the program is about to execute the cin statement (but it hasn't yet done so).

    Watching a Variable
    Suppose that you want to know the value that is currently stored in some variable. You can get this value by clicking in the code window and holding the mouse over the name of the variable in the code. Do this now with the height variable and you will most likely see a meaningless number. That is because we haven't yet put any value in the height variable. So, let's put a value in that variable and check it's value again:
    1. Press F10 to execute the cin statement.
    2. Type a number in the console window. I typed 42.8 and then pressed return.
    3. Check to see what value is now stored in the height variable (mine has 42.799999999999 (the reason for the difference is that not all real numbers can be exactly represented in the base 2 format that the computer uses).
    If you want to permanently watch the value of a variable, you can do so by clicking the Debug menu, choosing QuickWatch, typing the name of the variable, and then clicking the Add Watch button. Permanent watches are displayed in another small window below your code.

    Go ahead and put a permanent watch on the volume variable, then step through the program one line at a time until you notice that the volume variable has changed because of an assignment statement. Notice that when the value of the volume variable changed, its value in the watch window is displayed in red.

    Running to the Next Breakpoint
    For this step, please set another breakpoint at the bottom of your main function (on the return EXIT_SUCCESS line).

    If you want to run the program all the way to the next breakpoint, you may do so by pressing the F5 key. Try this now.

    Note: When you are running the program with debugging, it is a good idea to alway set a breakpoint on the last line of the main program. Otherwise the program will end and the console window will close before you can see the output.

    Summary of Compiler and Debugger Commands
    A summary of compiler and debugger commands is available online at www.cs.colorado.edu/~main/intro/lab/vscommands.html. I have this page bookmarked in the Firefox browser. Because I am using a Firefox Addon called "Foxmarks," this bookmark (and all my other bookmarks!) are available to me from any Firefox browser, even if I'm not working from home. It's pretty cool in a nerdish kind of way.
    Different Kinds of Errors
    • In the textbook, you'll read about three kinds of errors that a program might have. Briefly, the kinds of errors are:
      • Syntax Error: An error that occurs when the compiler does not understand what you have written. These are often small, such as a missing semi-colon.
      • Run-time Error: An error that occurs when a program is actually running. Typically, a run-time error causes a running program to stop immediately, and print an error message. For example, if a program includes an arithmetic expression x/y, and y happens to be zero—then a run-time error will occur when the expression x/y is encountered. But, this error does not occur until your program is actually running.
      • Logic Error: Sometimes your program compiles correctly, and has all the necessary directives, and runs without producing a run-time error. But, the answer that the program produces might still be wrong. These errors, also called “program bugs” are the toughest errors to find and eliminate.
      During the rest of this lab exercise, we’ll give you a program that has each of these kinds of errors. You’ll learn the typical ways of tracking down and elmininating these errors. The most important thing that you’ll do is continue to use the debugger, which is a tool to help you track down those elusive logic errors.
    Finding and Correcting the Syntax Error

    • Start a new CLR Empty Project called bugs and add the following bugs.cxx file:
      //****************************************************************************
      // ABOUT THIS PROGRAM (bugs.cxx)
      //   Written by: Michael Main, Aug 29, 1998
      //   Email address: main@colorado.edu
      //   Demonstration program for CSCI 1300, lab 2
      //
      // INPUT: The program prompts the user to enter the length of the base and
      //   upright side of a right triangle in inches.
      //
      // OUTPUT: The program calculates the length of the hypotenuse in inches.
      //   It also outputs the equivalent length in feet.
      //
      // EXAMPLE DIALOG:
      //   How tall is your right triangle in inches?
      //   3.0
      //   What is the base length of the right triangle in inches?
      //   4.0
      //   That triangle has a hypotenuse of 5.00000 inches.
      //   That is th same as 0.416667 feet.
      // NOTE: 
      //   This version of the program has three bugs in it for the exercise
      //   at http://www.cs.colorado.edu/~main/cs1300/cs1300-2.html
      //**************************************************************************
      
      #include <iostream>           // Provides cin, cout
      #include <cmath>              // Provides sqrt, pow
      #include <cstdlib>            // Provides EXIT_SUCCESS
      using namespace std;
      
      int main ( )
      {
          double height;              // Triangle's height (inches)
          double base;                // Triangle's base (inches)
          double sum_square;          // Sum of squares of height and base
          double hypotenuse;          // Triangle's hypotenuse (inches)
          double feet;                // Triangle's hypotenuse (feet)
          int   zero = 0;            // The number zero, to illustrate an error.
      
          // Input
          cout << "How tall is your right triangle in inches?" << endl;
          cin  >> height;
          cout << "What is the base length of the right triangle in inches?" << endl;
          cin  >> base
      
          // Computations
          sum_square = height*height + base*base;
          cout << 1/zero <<;
          hypotenuse = sqrt(sum_square);
          feet = (1/12) * hypotenuse;
      
          // Output answer
          cout << "The hypotenuse is " << hypotenuse << " inches." << endl;
          cout << "This is the same as " << feet << " feet." << endl;
      
          system("pause"); // Wait for the user to press a key
      
          return EXIT_SUCCESS;
      }
      
      This is a C++ program that I wrote. But I have made errors that you will fix. Start by trying to compile it in the usual way. The compiler will give a list of errors in an error window. These are usually syntax errors.

      When several syntax errors appear in the error window, always deal with the topmost error first. Often, if you fix the topmost error, then the others will disappear.

    • In this exercise, there is a syntax error. The error says something similar to this:
      error C2146: syntax error : missing ';' before identifier 'sum_square'
      
      This means that the compiler thinks that there is a something missing on or before line 46 of the program. To deal with this error, double click on the error message and notice that the cursor goes to line 46, where it thinks something is missing. That line looks like this:
      sum_square = height*height + base*base;
      
      But this line looks okay! There doesn't seem to be anything wrong before the '='. What is the compiler complaining about?

      When the compiler complains about a line, and you don’t see a problem, start looking at the previous lines in your program. Often the error will be one or two lines before the compiler’s guess.

    • In this exercise, the error is a few lines before line 46. Can you see this line in the code:
      cin >> base
      

      This line is missing the semicolon at the end. The compiler didn’t realize that the semicolon was missing until it got to line 46. In any case, you can fix the syntax error by placing a semicolon at the end of the statement cin >> base; Then recompile and move to the next step.

    Finding and Correcting the Run-time Error
    • Once more, compile your program. It should compile with no errors, and you can run the program. The program runs and asks you for some information. But after reading the information, the program crashes--maybe with that ominous "encountered a problem and needs to close" message from Windows.

      The message indicates that the program did something that the Windows operating system won't allow. In the case of this program, you might be able to figure out what caused the error by simply examining the program. But other times it's hard to see exactly where an error like this occurs, even if the crash message told you which line of code caused the problem. In such a case, the debugger can help you. The debugger lets you step through the program one line at a time, showing exactly which line is being executed.

      When you examine this program, you'll see that the problem is caused by a division by zero on line 47. Please delete this line now, recompile and move to the next step.

    Finding and Correcting the Logic Error
    • Finally the program is working. Or is it? There are no syntax or link errors. And there is no run-time error. But look at the answer that the program wrote:
      This is the same as 0 feet.
      
      That's not right!

      Even if a program compiles and runs without errors, you still must check that the output is correct.

      When a program has incorrect output, you can use the debugger to step through it one line at a time with the variables displayed. Go ahead and do this now, in the same way that you did before with a breakpoint on the first cout statement.

      Start the programming running, and when you reach the breakpoint, you should put watches on all five of the local variables. At this point, the values of the variables will look strange indeed. They are likely to contain garbage--whatever numbers happen to be in the computer’s memory at the moment. But, soon this will change. To see this change, run through the program, entering the number 30 for both pieces of data. After entering the second peice of data, the highlighted statement will be the assignment statement:

      sum_square = height*height + base*base;
      
      Execute this highlighted statement, and keep one eye on the variables. The value of sum_square should change to 1800 (if you used 30 for each input number). Then execute the next statement, and the value of hypotenuse will change to about 42. At this point you are about to execute the next assignment statement:
       feet = (1/12) * hypotenuse;
       
      Now, hypotenuse is around 42, so we would expect feet to be a bit less than 4. So, execute the statement, and oops! Why did feet change to zero?...

      The reason for the zero has to do with the factor (1/12) in the arithmetic expression. Remember that when C++ does division with integers, the answer is the quotient, and any remainder is thrown away. So 1/12 is actually zero. Here are two possible ways to fix the assignment statement:

      feet = hypotenuse/12;
      feet = (1.0/12.0) * hypotenuse;
      
      The first solution works okay because we are not dividing two integers (hypotenuse is a double number). The second line is another way to fix the problem becuase 1.0 and 12.0 are treated as non-integer numbers (the decimal point is enough to make them non-integer).

      Go ahead and make this last correction, and run the program once more.

    A Smooth Ending to the Program
      The end of our triangle program contains this line:
      system("pause"); // Wait for the user to press a key
      
      This statements allow for a more elegant end to the program by waiting for the user to press a key.

    Michael Main (main@colorado.edu)