Linux环境下的C/C++基础调试技术3――查看数据(一)

2014-11-24 12:59:16 · 作者: · 浏览: 0

本文首先以一个二叉树插入算法的实现作为例子说明GDB查看程序数据的相关方法,代码如下:

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: }
在调试这个二叉树插入程序的时候,我们会非常关心insert方法的执行情况,在进入那个while(1)循环后,我们可能会做以下的操作:

(gdb) p tmp->val
$1=12
(gdb) p tmp->left
$2 = (struct node *) 0x8049698
(gdb) p tmp->right
$3 = (struct node *) 0x0

这个操作显得累赘又麻烦,我们可以有以下的改进措施:

1.直接打印结构体tmp:

(gdb) p *tmp
$4 = {val = 12, left = 0x8049698, right = 0x0}

2.使用display命令:我们在#37设置断点,然后运行程序,待程序运行至该断点停下后使用display = disp 命令对某一个变量进行监视(之所以这样做是因为这个变量必须存在在该栈帧上,也就是说调试的时候这个变量的确被创建并且没有被销毁),程序以后只要一停止就打印这个变量的值在屏幕上:

(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}

也可以使用dis disp 1使这个监视动作失效(enable disp 1则恢复),undisp 1为删除。info display为查看当前所有自动打印点相关的信息

3.使用命令列表:在上篇中已经叙述,在此不再赘述。

4.使用call命令:我们在代码中已经有了一个打印整个树的函数printtree,使用call命令我们可以直接利用代码中的方法进行变量监视,在每次insert完成的时候调用printtree对二叉树进行打印:

(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.使用DDD的Data Window图形化表示:单击右键在root这个变量上然后选择display *root,每次在#37行停下时,在Data Window内对整个树的都有图形化表示,在左右子树上,你可以使用右键单击然后选择Display *()来显示。(Tips:你可以以--separate参数启动DDD,这样每个Window都是独立的,你可以获得更大的视野)。

补充:

1.打印数组:p *pointer@number_of_elements,其中number_of_elements表示显示pointer这个变量中的几个成员。另外一种方式是类型转换,例如下列程序:

1: int *x;

2: main()

3: {

4: x = (int *) malloc(25*sizeof(int));

5: x[3] = 12;

6: }
除了可以使用:

(gdb) p *x@25
$1 = {0, 0, 0, 12, 0 }

我们还可以使用:

(gdb) p (int [25]) *x
$2 = {0, 0, 0, 12, 0 }

2.打印本地变量:info locals,会打印当前栈帧的本地变量。

3.以不同形式打印变量:p/paramenters variable parameters 可以是 x 表示打印变量以十六进制表示,f为浮点,c为character,s为string。

4.打印历史查看过的变量:使用$number,而只使用$表示上一个变量。

(gdb) p tmp->left
$1 = (struct node *) 0x80496a8
(gdb) p *(tmp->left)
$2 = {val = 5, left = 0x