本文所结合图书及视频
一 、什么是 Bug
1、什么是 Bug
Bug 我们用中文解释过来的意思就是虫子、小病、(计算机程序中的)故障。1947年9月9日,葛丽丝·霍普(Grace Hopper)发现了第一个电脑上的Bug
。当在Mark II计算机上工作时,整个团队都搞不清楚为什么电脑不能正常运作了。经过大家的深度挖掘,发现原来是一只飞蛾意外飞入了一台电脑内部而引起的故障(如图所示)。这个团队把错误解除了,并在日记本中记录下了这一事件。也因此,人们逐渐开始用bug
来称呼计算机中的隐错。
第一次被发现的导致计算机错误的飞蛾,也是第一个计算机程序错误
二、什么是调试 有多重要?
1、什么是调试
上面我们讲到了在编写计算机程序的时候难免会出现 Bug
,那么也自然的需要Debug
也就是改错,调试了。 调试(Debugging/Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。
2、调试的基本步骤
① 发现程序错误的存在
② 以隔离、消除等方式对错误进行定位
③ 确定错误产生的原因
④ 提出纠正错误的解决方法
⑤ 对程序错误予以改正,重新测试
⑥ 如果以上操作完成还有错误,继续重复以上几步
对于一个程序错误而言能发现它的一般分为三类人:
① 程序员自己发现--------->程序员自己解决
② 测试人员发现-------->大部分bug由测试人员检测出
③ 客户或者用户发现情况严重
-------->尽可能不出现此情况
三、Debug 和 Release 的介绍
1、Debug版本
Debug通常称为调试版本,它包含调试信息,并且不做任何优化,方便于程序员调试程序。
2、Release版本
Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以方便于用户更好的使用。
#include
int main()
{
char *p = "hello xiaohuoban.";
printf("%s\n", p);
return 0;
}
上述代码在Debug环境的结果展示:
上述代码在Release环境的结果展示:
我们通过对比可以明显的看出两个不同环境下,生成的文件大小是不一样的,所以我们说调试就是在Debug版本的环境中,找代码中潜伏的问题的一个过程。那编译器进行了哪些优化呢?我们来看下面这段代码:
#include
int main()
{
int i = 0;
int arr[10] = { 0 };
for(i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("haha\n");
}
return 0;
}
如果是Debug模式去编译,程序的结果就是死循环。如果是Release模式去编译的话,程序没有死循环。那么他们之间的区别就是变量在内存中开辟的顺序发生了变化,影响到了程序执行的结果。
四、Windows 环境下 VS2019 调试介绍
在环境中选择Debug选项,才能使代码正常调试,Release选项下是无法调试代码的。
2、常用快捷键
通过上图我们也看到了一些关于调试的快捷键,相信大家都会熟能生巧的。下面我们来讲几个常用的快捷键:
F5 --> 启动调试,经常用来直接调到下一个断点处。
F9 -->创建断点和取消断点 断点
的重要作用,可以在程序的任意位置设置断点。这样就可以使的程序在我们想要的位置随意停止,继而一步步执行下去。
F10 -->逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
F11 -->逐语句,就是每次都执行一条语句,但是这个快捷键 可以使我们的执行逻辑 进入函数内部(这是最常用的)。
Ctrl + F5 --> 开始执行不调试,想让程序直接运行不调试可以直接使用该快捷键
有关更多的快捷键请参考这里VS2019调试代码快捷键
3、调试时查看当前程序信息
通过上图我们看到了进入调试以后会看到子菜单中,我们能用来观察当前程序的信息,例如:查看断点、查看局部变量、查看调用堆栈、查看内存、查看进程等等…大家可以根据自己的需要来选择要查看的选项,但前提是程序必须是在开启调试以后才能看到如此的子菜单
。
4、多动手,尝试调试,才能进步
一定要熟练掌握调试技巧
一个合格的程序员可能20%的时间在写代码,80%时间在调试代码
随着写的代码越多,接触的项目越大,会出现很多复杂的调试场景
多使用快捷键,能帮你提升工作效率
五、程序调试实例
实例一
实现代码: 求1!+2!+3!+4!+…n!; 不考虑溢出。
#include
int main()
{
int i = 0;
int sum = 0; //保存最终结果
int n = 0;
int ret = 1; //保存n的阶乘
scanf("%d", &n);
for(i = 1; i <= n; i++)
{
int j = 0;
for(j = 1; j <= i; j++)
{
ret *= j;
}
sum += ret;
}
return 0;
}
上图代码如果n取值为3的时候,运算结果是9,也就是1!+2!+3! = 1 + 2 + 6 = 9;但是实际运行结果却是15,这明显不符合我们的预期。那是哪里出现问题呢?
#include
int main()
{
int i = 0;
int sum = 0; //保存最终结果
int n = 0;
int ret = 1; //保存n的阶乘
scanf("%d", &n);
for(i = 1; i <= n; i++)
{
ret = 1; //进入循环每次更新ret从1开始
int j = 0;
for(j = 1; j <= i; j++)
{
ret *= j;
}
sum += ret;
}
return 0;
}
通过修改,程序运行后和我们预期的结果一样,程序测试通过。其他实例不再一一列举。
注意事项
① 程序运行不起来,应该是语法错误;程序可以运行起来,但不符合预期结果,称为运行时错误,调试解决的就是运行时错误!
② 调试时应该有一个预期,也就是程序运行到每一步应该是什么结果,当运行结果与预期不符时,就找到问题了!
六、如何写出好(易于调试)的代码
1、优秀的代码
1. 代码运行正常
2. Bug很少
3. 效率高
4. 可读性高
5. 可维护性高
6. 注释清晰
7. 文档齐全
2、常见的coding技巧
1.使用assert
2.尽量使用const
3.养成良好的编码风格
4.添加必要的注释
5.避免编码的陷阱
关于本节内容调试技巧
就讲到这,有关更多的调试技巧需要自己多动手去写,去实际调试,相信会随着编写代码量的增长,解决更多的Bug
后,大家都能掌握更多的调试技巧,下期我继续讲解C语言的数据的存储
内容。