Tutorial: Debugging in Dev C++ Introduction

advertisement
Debugger Tutorial
page 1
Tutorial: Debugging in Dev C++
Introduction
There are several types of errors that can occur at different stages of the programming process:
compiler errors, linker errors and run-time errors. In this tutorial we will discuss each type and
explain how you can use the tools provided by Dev C++ to find and correct them.
Compiler Errors
Description
These are the errors that are reported by the compiler. Usually they are simple syntax errors such
as misspelled words or missing punctuation.
Example
Let's try to compile the following program and see what happens:
int main()
{
cout << "Hello World!"
return 0;
}
The compiler gives us the following warnings and errors:
Line
3
File
c:\hello.cpp
c:\hello.cpp
4
c:\hello.cpp
Message
In function 'int main()':
'cout' undeclared (first use this function)
(Each undeclared identifier is reported only once for each function it appears in.)
expected ';' before "return"
First, we have a warning on line 3. It means that the compiler could not find a definition for
cout. We have made a mistake. The cout is defined in the standard library iostream which
should have been included in the program. We will also need to use the standard namespace.
We also have an error on line 4. This is easy to figure out. We left off the semi-colon on the
previous line.
Let's see what the corrected program looks like:
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World!";
return 0;
}
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 2
This program should compile without any errors.
Linker Errors
Description
These errors are caused when you forget to define or implement a function.
Example
Let's compile and link the following program:
void myFunction();
// prototype
int main()
{
myFunction ();
return 0;
}
The compiler will give us the following linker error:
Line
File
Message
c:\temp\ccURgaaa.o(text+)x2b) In function 'int main()':
[Linker error] undefined reference to 'myFunction()'
c:\temp\ccURgaaa.o(text+)x2b) ld returned 1 exit status
This is the linker's way of saying "I could not find a definition of function myFunction".
Although we provided a prototype for function myFunction, we never actually defined the
function.
Run-time Errors
Description
These are logical errors, that is, errors in the design of your program. They occur when you run
your program and they are the most difficult to find. The only indication that there is an error is a
wrong output or a fault that causes your program to crash. A program may run fine for years and
then suddenly crash on some input because of a logical error. That's why you should always test
your programs extensively.
The process of locating the source of logical errors and correcting them is called debugging. The
term was coined by Admiral Grace Hopper in the 1940s. According to her journal, when they
opened up a computer to try and find out why a program was not working, they discovered a
moth that had gotten inside and caused the problem. Since then, initially hardware and then
logical errors have been called "bugs".
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 3
A debugger is a tool that helps you find logical errors. It enables you to execute your program
one line at a time or in sections, to stop execution at a specific point and to check the values of
variables as you go along. This way, you can better understand how your program behaves (as
opposed to how you think it behaves) and find the exact location where the problem is. What the
debugger cannot tell you is why the problem occurs. This is something you have to figure out
yourself.
Debugging Method #1
A simple but often useful method of debugging is by inserting cout statements in various places
in the program. This enables us to:


Find out whether a specific part of the program is ever reached during execution.
Print out the values of different variables at specific points in the program.
Example
Let's say we have a want to read numbers from the user until the user enters 0. And we want to
find the product of all the integers. Say the user enters the numbers 2, 3, 4 and 0. We would
expect an output product of 24.
Here is the program:
#include <iostream>
using namespace std;
int main()
{
int num, product = 1;
do {
cout << "Enter a number (0 to exit): ";
cin >> num;
product *= num;
} while (num != 0);
cout << "Product = " << product << endl << endl;
system ("PAUSE");
return 0;
}
When we run the program, the output is:
Product = 0
Press any key to continue . . .
We can insert a cout statement right after the cin >> num statement, so that each number
being mulitplied into the product will be displayed (to verify the number read in is correct).
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 4
And we could also insert a cout statement right after the product is computed each time.
do {
cout << "Enter a number (0 to exit): ";
cin >> num;
cout << "
Multiply by " << num << endl;
product *= num;
cout << "
Running product " << product << endl;
} while (num != 0);
Now when we run the program, we can see that the last number multiplied is the 0, which was
supposed to indicate a stopping point:
Enter a number (0 to exit):
Multiply by 2
Running product 2
Enter a number (0 to exit):
Multiply by 3
Running product 6
Enter a number (0 to exit):
Multiply by 4
Running product 24
Enter a number (0 to exit):
Multiply by 0
Running product 0
Product = 0
2
3
4
0
Press any key to continue . . .
The while loop can be fixed as follows:
do {
cout << "Enter a number (0 to exit): ";
cin >> num;
if (num != 0)
product *= num;
} while (num != 0);
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 5
Debugging Method #2
Another method is to use the debugger that is built into the Dev C++ IDE. We will now learn
how to use the Dev C++ debugger to find the bugs in the following program:
Take a messed-up version of the fibonacci program presented earlier this week (week 5):
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int num1, num2,
seventh,
newTerm,
sum;
// First & second numbers in series
// Seventh term
// Next term in the series
// Running sum of elements
cout << "Enter the first two numbers of the series, separated by a space: ";
cin >> num1 >> num2;
cout << endl << endl << "The first 10 numbers in the Fibonacci series" << endl;
cout << "beginning with " << num1 << " and " << num2 << " are:" << endl;
cout << setw(5) << num1 << setw(5) << num2;
sum = num1 + num2;
// initial sum (first 2 terms)
for (int count = 3; count <= 10; ++count) // generate/display 3rd - 10th terms
{
if (count == 7)
seventh = newTerm;
// save seventh term
newTerm = num1 + num2;
sum += newTerm;
cout << setw(5) << newTerm;
num1 = num2;
num2 = newTerm;
}
cout << endl << endl;
cout << "The sum of the first 10 elements is " << sum << endl;
cout << "The seventh term (" << seventh << ") times 11 is " << seventh * 11 << endl;
cout << endl << endl;
system ("PAUSE");
return 0;
}
This program compiles and links successfully. Let's see what happens when we execute it:
Enter the first two numbers of the series, separated by a space: 4 5
The first 10 numbers in the Fibonacci series
beginning with 4 and 5 are:
4
5
9
14
23
37
60
97 157
254
The sum of the first 10 elements is 660
The seventh term (37) times 11 is 407
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 6
Press any key to continue . . .
There is obviously something wrong, because the sum of the first 10 elements was supposed to
be equal to the seventh term times 11.
Let's use the debugger to find out what:
Setting up the debugger (only the first time you use the debugger)
In order for the debugger to run correctly, you must check the following settings in your Dev
C++ IDE.
From the IDE main menu, choose Tools, then Compiler Options.
Click on the Settings tab. Then click on Linker in the left side of the window.
Under "Generate debugging information" in the right side of the window, make sure the
answer is "Yes" (change to "Yes" if necessary).
Click on Optimization in the left side of the window.
Under "Perform a number of minor optimizations" in the right side of the window, make
sure the answer is "No" (change to "No" if necessary).
Click the OK button at the bottom of the window.
Setting breakpoints
A breakpoint is a point in the program where you want the execution to stop temporarily so that
you can examine the values of variables. It allows you to run through portions of the program
that are correct and concentrate on those that aren't (or haven't been checked yet).
Let's say we decide to set a breakpoint within the if statement. Move the cursor to the beginning
of the line seventh = newTerm; and click in the tan strip to the left of the line.
A red dot with a checkmark will appear in the margin and the line will be highlighted in red:
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 7
Now, to run the program until the breakpoint, choose Debug, and Debug again from the main
menu,
OR click the Debug button (purple checkmark)
OR press the F8 key
All of this actions will start the debugger, and run the code until it hits a breakpoint.
For this program, you will need to enter the two integers for the program to get to the breakpoint.
Once we reach the breakpoint, the next line to be executed will be highlighted in blue.
Once we have reached the breakpoint, we want to check the contents of the variable newTerm to
make sure that it contains what we think it should.
Click on the Add Watch icon at the bottom of the screen
A "New Variable Watch" window will appear. Type the name of the variable, newTerm, into the
window and press the OK button:
The value of the newTerm will now show up under the debug tab in the frame to the left of your
code:
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 8
The newTerm value is 37. But wait! That is the value for the SIXTH term, not the seventh term!
Why did this happen? Something must have gone wrong.
First, let's stop the debugging process so that we may restart.
Clicking the Stop Execution button
Next, remove this breakpoint since it has served its purpose.
Move your mouse to the line where the breakpoint is and click on the red dot with the
green check in it
Now, we are going to go through the program one step at a time.
Stepping through the program
To step through the program, we use the following icons at the bottom of the screen:
Next Step is used to execute a single statement and jump to the
beginning of the next one. If the statement contains a function call, it execute the entire
function in one step.
Step Into is also used to execute a single statement. But if the
statement contains a function call, it will step into the function, so you can run the
function line by line.
Continue executes all statements up to the next breakpoint.
Run to Cursor executes all statements up to where the cursor is.
Warning: If you click the Step Into button at the wrong moment (on a line that calls a built-in
function) then you may step into the code for that standard function (such as sqrt) and its code
will then be displayed:
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 9
To exit this code, just click the Next Step icon.
We are ready to start the step-by-step execution of our program.
First click your cursor anywhere within the code of the first line of code within the main
function. The line will be highlighted in LIGHT blue:
Then click on the Run to Cursor button to start the debugger. The debugger will stop on the
first EXECUTABLE line of the main function (i.e. it will skip the variable declarations):
Notice that the dark blue highlighting the NEXT line to be executed.
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 10
Click on the Next Step button until you get to the cin line. Note that once you are there, when
you try to Next Step again, you can't. This is because cin is waiting for input from the keyboard.
Click on the button with the DOS screen icon
Type:
4 5
in your Task Bar to bring up the I/O window.
and press ENTER.
Click back on the IDE window to activate it.
Then press Next Step, until you enter the for loop:
Let's add a watch on the count variable.
Click the Add Watch button, type in count, and click OK.
Note: You can also add a variable to the watch window by "floating" your cursor over the name
of the variable within the source code side of the window. Try adding a watch on one of the
other variables using this method, before you continue.
Now press Next Step until the count changes to 7 in the debugger watch window.
At this point, our newTerm should be 60 ( the value of the 7th term). But it is not. It is still 37 in
the watch window.
The debugger told us where the problem is (newTerm contains the wrong value when it is saved).
If we are done, we can press Stop Execution, to stop the debugger session.
Now our brain has to figure out why this happened and how it can be fixed. The answer in this
case is that we must wait to save the seventh term until AFTER we compute the newTerm for
this loop.
©2008, Regis University
last mod 1-31-2008
Debugger Tutorial
page 11
So modify the for loop to be:
for (int count = 3; count <= 10; ++count) // generate/display 3rd - 10th terms
{
newTerm = num1 + num2;
sum += newTerm;
if (count == 7)
seventh = newTerm;
// save seventh term
cout << setw(5) << newTerm;
num1 = num2;
num2 = newTerm;
}
Debugger Notes:
- You can add watches to any variables within your code. However, their values will
only appear when you are stepping through code that is in the variable's scope.
- You can set multiple breakpoints within your code. Execution will pause each time a
breakpoint is encountered.
- Occasionally the Dev C++ debugger will lock up. If this happens, just press the Stop
Execution button and start again.
©2008, Regis University
last mod 1-31-2008
Download
Study collections