1.什么是bug
2.什么是调试(debug)
找到问题的过程叫调试,英文叫debug (消灭bug)
调试一个程序,首先是承认出现了问题,然后通过各种手段去定位问题的位置,可能是逐过程的调试,也可能是隔离和屏蔽代码的方式,找到问题所在位置,然后确定错误产生的原因,再修复代码,重新测试
3.debug和release
debug通常称为调试版本,包含调试信息,并不做任何优化,便于程序员调试程序
release称为发布版本,往往进行各种优化,使得程序在代码大小的运行速度上都是最优的,不包含调试信息
release版本和debug版本的对比:
release版本文件大小更小
测试人员测试的是release版本
4.VS调试快捷键
程序员怎么调试代码?
环境准备
需要一个支持调试的开发环境,应该把VS设置为Debug
调试快捷键
最常用的快捷键:
F9:创建断电和取消断点
断点的作用是可以在程序的任意位置设置断点,以暂停程序
条件断电:i=5是才触发断点
F5:启动调试,用来直接跳到下一个断点处
F10:逐过程,用来处理一个过程,一个过程可以是一次函数调用,或是一条语句,可以进行到函数内部
F11:逐语句,每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部,在函数调用的地方,想进入函数观察细节,就必须使用F10,直接完成函数调用
CTRL+F5:开始执行不调试,如果想让程序直接运行起来不调试就可以直接使用
5.监视和内存观察
观察代码的前提条件一定是开始调试后观察
监视
打开监视窗口
在监视窗口观察
内存
如果监视窗口看的不仔细,也可以观察变量在内存中的存储情况
在内存窗口中观察数据:
打开内存窗口后,要在地址栏输入:arr,&num,&c这类地址,就能观察到该地址的数据
除此之外,在调试的窗口中还有:自动窗口,局部变量,反汇编,寄存器等窗口
6.调试举例1
//求 1!+2!+3!+4!+...10! 的和
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
int c = 1;
int sum = 0;
for (i = 1; i <= 10; i++)
{
int c = 1;
for (j = 1; j <= i; j++)
{
c = c * j;
}
sum = sum + c;
}
printf("%d", sum);
return 0;
}
//代码优化
#include<stdio.h>
int main()
{
int i = 0;
int c = 1;
int sum = 0;
for (i = 1; i <= 10; i++)
{
c = c * i;
sum = sum + c;
}
printf("%d", sum);
}
7.调试举例2
#include<stdio.h>
int main()
{
int i = 0;
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}
结果为死循环打印hehe
地址相同
1. 栈区内存的使用习惯是从高地址向低地址使用的,所以变量i的地址是较大的。arr数组的地址整体是小于i地址的
2。数组在内存中的存放时,随着下标的增长,地址是由低到高变化的
如果是上面的内存布局,那么随着数组下标的增长,往后越界就有可能覆盖到i,这样就会造成死循环。
8.调试举例3
复杂代码调试
演示:
在函数内部打断点,快速跳转到函数
在数组传参,调试进入函数时,如何在监视窗口观察数组内容:数组名,n的形式
一维数组通过形参关键数组的内容
二维数组通过形参关键数组内容
9.编程常见错误归类
编译型错误
编译型错误一般都是语法错误,在编译时就能发现,这类错误一般看错误信息就能找到一些蛛丝马迹,双击错误信息也能初步跳转到代码错误的地方或附近。编译错误随语言的熟练掌握会越来越少
链接型错误
看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在,一般是因为:
标识符名不存在
拼写错误
头文件没包含
引用的库不存在
LNK为link缩写,链接
运行时错误
运行时错误,是千变万化的,需要借助调试,逐步定位问题,调试解决的是运行时的问题