Use DDD for program debugging | |
Assertion |
The purpose of debugger such as DDD is to allow you to see what is going on "inside" another program while it executes ---- or what another program was doing at the moment it crashed.
DDD can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:
Start your program, specifying anything that might affect its behavior. | |
Make your program stop on specified conditions. | |
Examine what has happened, when your program has stopped. | |
Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another. |
Download the program sample.cpp. Compile it to generate executable file: sample
Normally, sample should sort and print its arguments numerically, as in the following example:
>> ./sample 8 7 5 4 1 3
1 3 4 5 7 8
However, with certain arguments, this goes wrong:
>> ./sample 8000 7000 5000 1000 4000
0 1000 4000 5000 7000
Let us use ddd to see what is going on:
First, you must compile ‘sample.c’ for debugging, giving the ‘-g’ flag while compiling: (see compiling for debugging) |
>> gcc -g -o sample sample.cpp
Then, you can invoke ddd on the sample executable: (see getting in and out of DDD) |
>> ddd sample
And then begin debugging ... ...
Type ‘ddd’ to start ddd |
|
Use ‘File> Exit’ or Ctrl+ Q to exit |
ddd is composed of three main windows. From top to bottom, we have:
The Data Window shows the current data of the debugged program. |
|
The Source Window shows the current source code of the debugged program. |
|
The Debugger Console accepts debugger commands and shows debugger messages. |
Compiling for Debugging
In order to debug a program effectively, you need to generate debugging information when you compile it. This debugging information is stored in the object file; it describes the data type of each variable or function and the correspondence between source line numbers and addresses in the executable code.
To request debugging information, specify the ‘-g’ option when you run the compiler.
Note: When you debug a program compiled with ‘-g -o’, remember that the optimizer is rearranging your code; the debugger shows you what is really there. Do not be too surprised when the execution path does not exactly match your source file! An extreme example: if you define a variable, but never use it, ddd never sees that variable—because the compiler optimizes it out of existence.
Breakpoints
|
|||||||
Watchpoints
|
|||||||
Interrupting |
If the program is already running, you can interrupt it any time by clicking the ‘Interrupt’ button.
‘Interrupt’ and
'ESC' button also interrupt a running debugger command, such as printing data.
Instead of using debugger in C++. Many of the techniques used in writing robust in C++ code. For example, if you have a function that is supposed to be passed a person's name, as a char*, it would be wise to say:
#include <assert.h>void f (char* name)
{
assert(name && *name);...
}
to perform basic checks on the passed-in pointer. assert() is a function (actually a macro) that checks whether its argument is true (non-zero), and aborts the program if not.
C++ offers additional opportunities to the designer interested in producing
quality code. For example, consider a common problem in C++, where array
boundary index are not checked during a dereference operation, and a bad
location is accessed or written to.
int arr[3];
i = 103;
assert (i < 3);
arr[i] = 151;
Then assert () will abort the program and report the line of error occur as the index of this array is out of bound.
Download program: test2.cpp and file mark.txt (input file in the program).
Try to use the debugging tools to find out the error in the program and correct it. The output file should be: grade.txt.
Here is the solution.