Debugging

Debugging is a programming term used to describe the locating and correcting of errors in a program. Often, but not always, the most demanding part of it is locating the error.

In order to try and find the error, you must be aware of its existence. You can achieve that only by testing the program with different inputs and comparing the results with the results you know are correct. The basic ideas of testing were shortly discussed on the previous programming course.

Here, we are going to introduce you to the general principles of a couple of useful mechanisms for searching for the reason of the error once you have noticed your program works incorrectly.

The first mechanism is test printing. It was used especially on the previous programming course. Test printing means that you add print commands (print, cout) into the code around the expected error, purely with the purpose of testing the code. They show you how the program proceeds and how the values of interesting variables change. The idea is, of course, that you can determine where the error is by reasoning, after you have looked at the printed variable values and the printing order of the test prints. There is no reason to discuss test printing further, because you are already familiar with it as a debugging mechanism.

Another error tracing mechanism, and often much more user-friendly, is the use of a so-called debugger. A debugger is a separate program that provides an environment in which to execute the program you want to test.

The use and functionality of a debugger depend on the programming language and the compiler or interpreter you use, but typically, it supports at least the following operations, in one way or another:

  • setting breakpoints (with either arrival on the line, calling a certain function, or handling a variable as the criteria)
  • executing the program one command or function at a time (stepping)
  • observing the state (value) of the variables
  • observing the hierarchy of function calls (stack trace).

Usually, you locate the error following steps like these:

  1. Get a rough estimate of the error’s location (in other words, make an educated guess on where the error could be located). You can do this either by testing or, if the program crashes during execution, with a debugger.
  2. Set the breakpoint before the assumed error, and run the program within the debugger.
  3. Execute the program from the breakpoint onwards, one command at a time, and observe how e.g. the variable values and return values of the functions change, until you can, hopefully, deduce the reason of the error.
  4. If you cannot locate the error on your first try, it is usually a good idea to try and find the error location by moving the breakpoint forward or back.