2012年(23)
分类: LINUX
2012-07-10 11:57:54
观察点:
点击(此处)折叠或打开
1. #include <stdio.h>
2.
3. int main(void)
4. {
5. int sum = 0, i = 0;
6. char input[5];
7.
8. while (1) {
9. sum = 0;
10. scanf("%s", input);
11. for (i = 0; input[i] != '\0'; i++)
12. sum = sum*10 + input[i] - '0';
13. printf("input=%d\n", sum);
14. }
15. return 0;
16. }
点击(此处)折叠或打开
1. $ gdb main
2. ...
3. (gdb) start
4. Breakpoint 1 at 0x80483b5: file main.c, line 5.
5. Starting program: /home/akaedu/main
6. main () at main.c:5
7. 5 int sum = 0, i = 0;
8. (gdb) n
9. 9 sum = 0;
10. (gdb) (直接回车)
11. 10 scanf("%s", input);
12. (gdb) (直接回车)
13. 12345
14. 11 for (i = 0; input[i] != '\0'; i++)
15. (gdb) p input
16. $1 = "12345"
input数组只有5个元素,写出界的是scanf自动添的'\0',用x命令看会更清楚一些
点击(此处)折叠或打开
1. (gdb) x/7b input
2. 0xbfb8f0a7: 0x31 0x32 0x33 0x34 0x35 0x00 0x00
x命令打印指定存储单元的内容。7b是打印格式,b表示每个字节一组,7表示打印7组[],从input数组的第一个字节开始连续打印7个字节。前5个字节是input数组的存储单元,打印的正是十六进制ASCII码的'1'到'5',第6个字节是写出界的'\0'。根据运行结果,前4个字符转成数字都没错,第5个错了,也就是i从0到3的循环都没错,我们设一个条件断点从i等于4开始单步调试:
点击(此处)折叠或打开
1. (gdb) l
2. 6 char input[5];
3. 7
4. 8 while (1) {
5. 9 sum = 0;
6. 10 scanf("%s", input);
7. 11 for (i = 0; input[i] != '\0'; i++)
8. 12 sum = sum*10 + input[i] - '0';
9. 13 printf("input=%d\n", sum);
10. 14 }
11. 15 return 0;
12. (gdb) b 12 if i == 4
13. Breakpoint 2 at 0x80483e6: file main.c, line 12.
14. (gdb) c
15. Continuing.
16.
17. Breakpoint 2, main () at main.c:12
18. 12 sum = sum*10 + input[i] - '0';
19. (gdb) p sum
20. $2 = 1234
现在sum是1234没错,根据运行结果是123407我们知道即将进行的这步计算肯定要出错,算出来应该是12340,那就是说input[4]肯定不是'5'了,事实证明这个推理是不严谨的:
点击(此处)折叠或打开
1. (gdb) x/7b input
2. 0xbfb8f0a7: 0x31 0x32 0x33 0x34 0x35 0x04 0x00
从头执行程序,重复上次的输入,用watch命令设置观察点,跟踪input[4]后面那个字节(可以用input[5]表示,虽然这是访问越界)
点击(此处)折叠或打开
1. (gdb) delete breakpoints
2. Delete all breakpoints? (y or n) y
3. (gdb) start
4. Breakpoint 1 at 0x80483b5: file main.c, line 5.
5. Starting program: /home/akaedu/main
6. main () at main.c:5
7. 5 int sum = 0, i = 0;
8. (gdb) n
9. 9 sum = 0;
10. (gdb) (直接回车)
11. 10 scanf("%s", input);
12. (gdb) (直接回车)
13. 12345
14. 11 for (i = 0; input[i] != '\0'; i++)
15. (gdb) watch input[5]
16. Hardware watchpoint 2: input[5]
17. (gdb) i watchpoints
18. Num Type Disp Enb Address What
19. 2 hw watchpoint keep y input[5]
20. (gdb) c
21. Continuing.
22. Hardware watchpoint 2: input[5]
23.
24. Old value = 0 '\0'
25. New value = 1 '\001'
26. 0x0804840c in main () at main.c:11
27. 11 for (i = 0; input[i] != '\0'; i++)
28. (gdb) c
29. Continuing.
30. Hardware watchpoint 2: input[5]
31.
32. Old value = 1 '\001'
33. New value = 2 '\002'
34. 0x0804840c in main () at main.c:11
35. 11 for (i = 0; input[i] != '\0'; i++)
36. (gdb) c
37. Continuing.
38. Hardware watchpoint 2: input[5]
39.
40. Old value = 2 '\002'
41. New value = 3 '\003'
42. 0x0804840c in main () at main.c:11
43. 11 for (i = 0; input[i] != '\0'; i++)
已经很明显了,每次都是回到for循环开头的时候改变了input[5]的值,而且是每次加1,而循环变量i正是在每次回到循环开头之前加1,原来input[5]就是变量i的存储单元,换句话说,i的存储单元是紧跟在input数组后面的。
本章学习的命令:
命令 |
描述 |
watch |
设置观察点 |
info(或i) watchpoints |
查看当前设置了哪些观察点 |
x |
从某个位置开始打印存储单元的内容,全部当成字节来看,而不区分哪个字节属于哪个变量 |