This article first describes how to view program data using GDB using the implementation of a Binary Tree Insertion Algorithm. The Code is as follows:
1: // bintree. c: routines to do insert and sorted print of a binary tree
2:
3: # include
4: # include
5:
6: struct node {
7: int val; // stored value
8: struct node * left; // ptr to smaller child
9: struct node * right; // ptr to larger child
10 :};
11:
12: typedef struct node * nsp;
13:
14: nsp root;
15:
16: nsp makenode (int x)
17 :{
18: nsp tmp;
19:
20: tmp = (nsp) malloc (sizeof (struct node ));
21: tmp-> val = x;
22: tmp-> left = tmp-> right = 0;
23: return tmp;
24 :}
25:
26: void insert (nsp * btp, int x)
27 :{
28: nsp tmp = * btp;
29:
30: if (* btp = 0 ){
31: * btp = makenode (x );
32: return;
33 :}
34:
35: while (1)
36 :{
37: if (x <tmp-> val ){
38:
39: if (tmp-> left! = 0 ){
40: tmp = tmp-> left;
41:} else {
42: tmp-> left = makenode (x );
43: break;
44 :}
45:
46:} else {
47:
48: if (tmp-> right! = 0 ){
49: tmp = tmp-> right;
50:} else {
51: tmp-> right = makenode (x );
52: break;
53 :}
54:
55 :}
56 :}
57 :}
58:
59:
60: void printtree (nsp bt)
61 :{
62: if (bt = 0) return;
63: printtree (bt-> left );
64: printf ("% d", bt-> val );
65: printtree (bt-> right );
66 :}
67:
68:
69: int main (int argc, char * argv [])
70 :{
71: root = 0;
72: for (int I = 1; I <argc; I ++)
73: insert (& root, atoi (argv [I]);
74: printtree (root );
75 :}
When debugging this binary tree insert program, we are very concerned about the execution of the insert method. After Entering the while (1) loop, we may perform the following operations:
(Gdb) p tmp-> val
$1 = 12
(Gdb) p tmp-> left
$2 = (struct node x) 0x8049698
(Gdb) p tmp-> right
$3 = (struct node *) 0x0
This operation is cumbersome and troublesome. We can take the following improvement measures:
1. Print the struct tmp directly:
(Gdb) p * tmp
$4 = {val = 12, left = 0x8049698, right = 0x0}
2. run the display command: Set the breakpoint in #37, and then run the program, after the program runs to the breakpoint, use the display = disp command to monitor a variable (this is because the variable must exist on the stack frame, that is to say, this variable is indeed created and not destroyed during debugging.) After the program stops, the value of this variable will be printed on the screen:
(Gdb) disp * tmp
1: * tmp = {val = 12, left = 0x8049698, right = 0x0}
(Gdb) c
Continuing.
Breakpoint 1, insert (btp = 0x804967c, x = 5) at bintree. c: 37
37 if (x <tmp-> val ){
1: * tmp = {val = 8, left = 0x0, right = 0x0}
You can also use dis disp 1 to disable this monitoring action (enable disp 1 is restored), and undisp 1 is deleted. Info display is used to view information related to all current automatic printing points.
3. Use the command list: it is described in the previous article and will not be repeated here.
4. call Command: We have a function printtree in the code that prints the entire tree. Using the call Command, we can directly use the method in the code to monitor variables, call printtree to print Binary Trees upon each insert:
(Gdb) commands 2
Type commands for when breakpoint 2 is hit, one per line.
End with a line saying just "end ".
> Printf "************ current tree ***********"
> Call printtree (root)
> End
5. use the Data Window graphical representation of DDD: Right-click the variable "root" and select "display * root". Every time you stop at line #37, graphical representation of the entire tree is provided in the Data Window. in the left and right Subtrees, you can right-click and select Display. (Tips: You can start DDD with the -- separate parameter, so that each Window is independent and you can gain a larger view ).
Supplement:
1. Print the array: p * pointer @ number_of_elements. number_of_elements indicates several members in the pointer variable. Another method is type conversion, such as the following program:
1: int * x;
2: main ()
3 :{
4: x = (int *) malloc (25 * sizeof (int ));
5: x [3] = 12;
6 :}
In addition to the following:
(Gdb) p * x @ 25
$1 = {0, 0, 0, 12, 0}
We can also use:
(Gdb) p (int [25]) * x
$2 = {0, 0, 0, 12, 0}
2. Print the local variable: info locals. The local variable of the current stack frame is printed.
3. Print variables in different forms: p/paramenters variable parameters can be x to indicate that the printed variables are represented in hexadecimal notation, f is a floating point, c is character, and s is a string.
4. Print the variables that have been viewed in history: use $ number instead of $ to represent the previous variable.
(Gdb) p tmp-> left
$1 = (struct node *) 0x80496a8
(Gdb) p * (tmp-> left)
$2 = {val = 5, left = 0x0, right = 0x0}
(Gdb) p * $1
$3 = {val = 5, left = 0x0, right = 0x0}
(Gdb) p tmp-> left
$1 = (struct node *) 0x80496a8
(Gdb) p * $
$2 = {val = 5, left = 0x0, right = 0x0}
5. Modify the variable value when the debugged program runs: set x = 12.
6. Use custom variables for debugging: for example,
1: int w [4] = {12, 5, 8, 29 };
2: main ()
3 :{
4: w [2] = 88;
5 :}
We set I and use this variable to traverse the array:
(Gdb) set $ I = 0
(Gdb) p w [$ I ++]
$1 = 12
(Gdb)
$2 = 5
(Gdb)
$3 = 88
(Gdb)
$4 = 29
7. Force Type Printing
P {type} address: the memory specified by address is interpreted as the type (similar to forced transformation and enhanced)
8. Set some common options
1) set print array: Open the array display. When the array is displayed, each element occupies one row. If the array is not displayed, each element is separated by a comma. Disabled by default
2) set print elements num-of-elements: set the number of elements displayed when GDB prints data. The default value is 200. If it is set to 0, it indicates no limit (unlimited)
3) set print null-stop: When GDB is used to print the character array, it is stopped when NULL is encountered and disabled by default.
4) set print pretty: when setting the GDB print structure, each row has a member with corresponding indentation, Which is disabled by default.
5) set print object: print the actual type when setting the GDB printing polymorphism type. The default value is disabled. <