Debugging Your Program

Debugging Your Program


I feel that this is a topic that needs to be covered in detail. As it is, debugging is an incredibly important part of programming. If you run upon errors, you need to know how to find the issue, and resolve it. If you’re missing a semi-colon, you shouldn’t have to make a post to figure that out.
Please keep in mind that this isn’t specifically how you should debug. It isn’t a set of rules, it’s a set of recommendations. My recommendations may not necessarily be proper practice. If anything incorrect is found in this article please post so I can fix it. I don’t like to spread false knowledge.

Anyway, we’ll start basic, from acknowledging and understanding a compiler error, to single-stepping through a program with your IDE’s debugger.

Please note: I’m referencing C++ for Dummies 5th Edition by Stephen Randy Davis, pages 139-155.

Identifying An Error


Often times your program doesn’t work as planned, and won’t compile properly. Even the best programmers make mistakes, being able to identify what you did wrong is essential. There are two types of errors that exist; those that the C++ compiler can catch on its own, and those that the compiler can’t catch. Errors that C++ can catch are known as compiler-time errors. Compiler-time errors should be relatively easy to fix, because the compiler points you to where the problem is. All that garbage that’s spit out by the compiler has some use. Here’s an example. I forgot to put a semicolon after my return statement.
1
2
3
4
int main()
{
return 0
}

Your compiler should generate an error something like…
\main.cpp(4) : error C2143: syntax error : missing ';' before '}'
Compiler errors differ from compiler to compiler, but its all going to generally be the same. In my case, I’m using Visual Studio 2008, but if you’re using Dev-C++, or G++, the same thing applies.
Now lets take this compiler error apart. The first part of it \main.cpp(4) says that the error is in the file main.cpp, on line 4. After that is error C2143: That’s the compiler specific error code. If you’re using Visual Studio, you can easily look up the error code on MSDN if you need to. After that the error states syntax error : Which tells you that you messed up some syntax. So you must not have typed something right. Then it tells me missing ‘;’ before ‘}’ There’s a missing semi-colon before a closing bracket. Okay, so I know I’m missing a semi-colon, I know the error is on line 4, I know that its before the closing bracket. So I go to main.cpp, line 4, and before the closing bracket I need a semi-colon. Since the only thing that’s on line 4 is a closing bracket, I’ll just go up to line three and OH! I notice I forgot to put a semi-colon after return 0. Aknowledging a compiler error should be as easy as that.
The other type of error that C++ doesn’t catch, is called a run-time error. Run-time errors are often much more tricky to catch.

Debugging Techniques


There’s several ways that one can debug a program. The two that I use most often are the WRITE technique, and single-step debugging. Firstly, I’ll cover the WRITE technique. It invovles creating output statements for all of your variables, so you can see the value of everything. I’ll use this program example from C++ for Dummies 5th edition.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// ErrorProgram – This program averages a series
//		 of numbers, except that it contains
//		 a fatal bug.
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;

int main(int nNumberofArgs, char *pszArgs[])
{
	cout << "This program is designed to crash!"
		 << endl;

	int nSum;
	int nNums;

	// accumulate input numbers until the
	// user enteres a negative number, then
	// return the average
	nNums = 0;
	while(true)
	{
		// enter another number to add
		int nValue;
		cout << "Enter another number:";
		cin >> nValue;
		cout << endl;

		// if the input number is negative...
		if(nValue < 0)
		{
			// ... then output the average
			cout << "Average is: "
				 << nSum/nNums
				 << endl;
			break;
		}

		// not negative, add the value to
		// the accumulator
		nSum += nValue;
	}

	cin.ignore(10000, '\n');
	return 0;
}


When executing this code, you’ll get a run-time error. An easy way to solve what’s being messed up is using the WRITE technique. Every time you go into the while loop, have it output the value of nNums.

1
2
3
4
5
6
7
While(true)
{
	// output
	cout << “nNums = “ << nNums << endl;
	
	// The rest of the program is unchanged
}


Output will look like

This program is designed to crash!
nNums = 0
Enter another number:1

nNums = 0
Enter another number:2

nNums = 0
Enter another number:3

nNums = 0 
Enter another number:


You can see that nNums is being initialized to 0, but where is it being incremented? It’s not, and this is the bug. Clearly nNums should have been incremented during each loop of the input section. By using the WRITE technique, we told out program to output the value of nNums every loop, thereby finding out that it wasn’t being properly incremented.

For smaller program, the WRITE technique works reasonably well, but as things get larger, it’s harder to output all your variables, and it just starts to seem like a waste of time. Instead, we’ll rely on the debugger. First, lets define a debugger. A debugger is a tool built into most development environments (and although they differ, most debuggers work on the same principles.) A programmer controls the debugger through commands by the means of the same interface as the editor. You can access these commands in menu items or by using hotkeys. The debugger allows the programmer to control the execution of his/her program. He/she can execute one step at a time in the program, he/she can stop the program at any point, and he/she can examine the value of variables. To appreciate the power of the debugger, you need to see it in action. Using this is hard to explain in words (and I’m terrible at putting things into words.) So for further information on debugging, I’ll link you to a very handy web page. http://www.cprogramming.com/tutorial/debugging_concepts.html


If there’s anything that needs to be added, let me know.


While I was proof reading, I’m noticing I’m doing a terrible job at explaining this. The post is open for improvements.

-Thumper
Debugging doesn't refer to removing compiler errors, does it? Maybe you could split it into "Compile-time (compiler) Errors", "Runtime Errors" and "Bugs".

Also you should mention assertions. Assertions are incredibly useful because you can sprinkle them throughout your code, and, rather than having to remove them, you can just stick "#define NDEBUG" in a global header file (make sure it's the first thing included in any file) and the assertions get turned into null statements by the preprocessor.
Last edited on
I use debugging in two different ways. Debugging in the sense of literally debugging your program (removing bugs) and debugging as an entity, the debugger you use to single-step through programs.

I think later in the day i'll modify it to the three sections you suggested, that's a good idea.
As for assertions, i'm not very familiar with them. If you could link me to a page with some knowledge on them, I'd gladly look into it.
Last edited on
Topic archived. No new replies allowed.