I would really like to learn how to debug my programs. The book I'm using does not have much info on debugging and my instructor hasn't said much on the topic either. I ended up re-writing my source code because of seg fault error. The program works fine now, but I'm sure I would have saved a lot of time by debugging the program instead.

>but I'm sure I would have saved a lot of time by debugging the program instead.
Sometimes debugging is more efficient and cost effective, but sometimes the bug is just too engrained and a rewrite is in order.

>I would really like to learn how to debug my programs.
Start out like we all did: sprinkle print statements all over the place. The two types you'll use most often are "got here" statements:

// Lots of code
cerr<<"Got here"<<endl;
// More code
cerr<<"Got here"<<endl;

When you have a difficult bug, start with the "got here" statement at the end of the program and move it steadily back until you pinpoint the location of the error. However, finding the source of the error is more difficult, and that brings us to the second type of print statement you'll use, watch statements:

T *p;
// Do stuff with p
cout<< p << *p;

Every time you trace errors to a particular variable, print its address and contents throughout the execution of the program. This way you can see if it takes on a value that would result in your error.

These two simple debugging tricks can help you find a surprising number of bugs, and you don't have to know esoteric debugging software. Though keep in mind that knowing how to use debugging software like gdb will save you a lot of time, and sometimes heavily editing the source isn't an option, so you can't use debug prints unless they were there originally.

Thanks for the advice Narue, I'm sure it will help me in writing future programs.

Another thing to do is to add 'assert( <expression> )' statements to your code. These can test expected conditions, such as the range of values for a parameter to a function:

#include <assert.h>

void FetchRecord( int recordNumber )
{
    assert( recordNumber >= 0 );  // no negative record numbers, please!
    <blah blah blah>
}

If somehow you were to call this function with a negative recordNumber during your testing, the program would stop and you would get an error message about the assert being incorrect at line n of <filename>.

The assert, depending on your compiler, usually only evaluates the expression when compiled in 'debug' mode. in 'release' mode assert does NOT evaluate the expression inside the parens and so costs you nothing in your final code.

By checking 'invariants', like the range of values expected, you can eliminate a whole class of problems where you use a function or algorithm in an unexpected way. Sprinkle these liberally around your code and they can save you a whole bunch of debugging time, without costing any release-mode runtime penalties.

But, the general rule is: don't use asserts to check data that comes from outside your code, such as user input or stuff read from a file. Check things that your code does. The reason not to check user input in asserts is two-fold; one the assert error message isn't very friendly to anyone but the programmer, and two the assert won't do anything in your released product.

This article has been dead for over six months. Start a new discussion instead.