1、单步调试
在实际开发中,常常会出现这样的情况,我们可以大致把出现问题的代码锁定在一定范围内,但无法确定到底是哪条语句出现了问题,该怎么办呢?按照前面的思路,必须要在所有代码行前面设置断点,让代码一个断点一个断点地执行。
这种方案确实可行,但很麻烦,也不专业,这节我们就来介绍一种更加便捷的调试技巧——单步调试。所谓单步调试,就是让代码一步一步地执行。
下面的代码用来求一个等差数列的和,我们以该代码来演示单步调试:
1. #include <stdio.h>
2. int main(){
3. int start, space, length, i, thisNum;
4. long total = 0;
5.
6. printf("请输入等差数列的首项值:");
7. scanf("%d", &start);
8. printf("请输入等差数列的公差:");
9. scanf("%d", &space);
10. printf("请输入等差数列的项数:");
11. scanf("%d", &length);
12.
13. for(i=0; i<length; i++){
14. thisNum = start + space * i;
15. if( length-i > 1 ){
16. printf("%d + ", thisNum);
17. }else{
18. printf("%d", thisNum);
19. }
20. total += thisNum;
21. }
22. printf(" = %ld\\n", total);
23.
24. return 0;
25. }
在第 6 行设置一个断点,然后点击“逐过程调试”按钮,或者按 F10 键,程序就会运行到下一行并暂停:
再次点击“逐过程”按钮或按 F11 键,就会执行第 7 行代码,要求用户输入数据。用户输入结束后,黄色箭头就会指向第 8 行,并暂停程序。如此重复执行上面的操作,就可以让程序一条语句一条语句地执行,以观察程序的内部细节,这就称为单步调试。
逐过程调试(F10)和逐语句调试(F11)
刚才我们在第 6 行设置了断点,按下“逐过程”按钮或 F10 键,程序就会执行 printf(),并暂停在下一行代码处。
printf() 是一个函数,它本身由多条语句构成,如果你希望进入 printf() 函数内部,查看整个函数的执行过程,可以点击“逐语句”按钮,或者按 F11 键,这样程序就会进入 printf() 所在的源文件,如下图所示:
当需要跳出函数时,可以点击“跳出”按钮,或者按 Shift+F11 键,就会返回刚才的代码。
逐过程(F10)和逐语句(F11)都可以用来进行单步调试,但是它们有所区别:
逐过程(F10)在遇到函数时,会把函数从整体上看做一条语句,不会进入函数内部;
逐语句(F11)在遇到函数时,认为函数由多条语句构成,会进入函数内部。
逐语句(F10)不仅可以进入库函数的内部,还可以进入自定义函数内部。在实际的调试过程中,两者结合可发挥更大的威力。
断点 + 查看/修改变量 + 逐过程调试 + 逐语句调试,这足以解决绝大多数逻辑问题,到此,初学者就已经学到了调试的基本技能。
修改代码运行位置
在 VS 中,调试器还允许我们直接跳过一段代码,不去执行它们。将下面的代码复制到源文件:
1. #include <stdio.h>
2. int main(){
3. printf("111\\n");
4. printf("222\\n");
5. printf("333\\n");
6. printf("444\\n");
7. printf("555\\n");
8. printf("666\\n");
9. return 0;
10. }
在第 3 行设置断点,开始单步调试。假设我们不希望执行 4~6 行的代码,那么当程序执行到第 4 行时,可以将鼠标移动到黄色箭头处,直接向下拖动到第 7 行,如下图所示:
程序执行完成后,在控制台上会输出: 111 555 666
注意:随意修改程序运行位置是非常危险的行为,假设我们定义了一个指针,在第 N 行代码中让它指向了一个数组,如果我们在修改程序运行位置的时候跳过了第 N 行代码,并且后面也使用到了该指针,那么就极有可能导致程序崩溃。
2、即时窗口的使用
“即时窗口”是 VS 提供的一项非常强大的功能,在调试模式下,我们可以在即时窗口中输入 C 语言代码并立即运行,如下图所示:
在即时窗口中可以使用代码中的变量,可以输出变量或表达式的值(无需使用 printf()函数),也可以修改变量的值。
即时窗口本质上是一个命令解释器,它负责解释我们输入的代码,再由 VS 中的对应模块执行,最后将输出结果呈现到即时窗口。
需要注意的是,在即时窗口中不能定义新的变量,因为程序运行时 Windows 已经为它分配好了只够刚好使用的内存,定义变量是需要额外分配内存的,所以调试器不允许在程序运行的过程中定义变量,因为这可能会导致不可预知的后果。
调用函数
在即时窗口中除了可以使用代码中的变量,也可以调用代码中的函数。将下面的代码复制到源文件中:
1. int plus(int x, int y){
2. return x + y;
3. }
4. int main(){
5. return 0;
6. }
在第 6 行设置断点,并在即时窗口中输入 plus(5, 6),如下图所示: