代码报错 | 出bug-->该如何调试?
- 什么叫做bug
- 调试是什么?有多重要?
- Debug和Release的介绍
- 调试
- 常用的快捷键
- 调试时查看程序当前的信息
- 如何写出好(易于调试)的代码
- 对const的通俗生活中举例
- assert的理解
- 编译常见的错误
什么叫做bug
世界上第一个bug
计算机刚出现时,是个庞然大物。突然有一天工作人员发现计算机无法正常工作了,结果是在晶体管上发现了一只昆虫的尸体
调试是什么?有多重要?
所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩饰,也就没有迹象了,如果问心有愧,就必然需要掩饰,那就一定会有迹象,迹象越多就越容易顺藤摸瓜,这就是推理的途径。
一名优秀的程序员是一位出色的侦探。
每一次调试都是尝试破案的过程
我们是如何写代码的呢?
如何修改bug的呢?
迷信式修bug
调试
又称为除错,是发现和减少计算机程序或者电子仪器设备中程序错误的一个过程
步骤:
- 发现程序错误的存在
- 以隔离,消除等方式对错误进行定位
- 确定错误产生的原因
- 提出纠正错误的解决方法
- 对程序错误给予改正,重新测试
Debug和Release的介绍
Debug:
通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序
Release:
称为发布版本(给用户使用),它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户可以很好的使用
调试
- 把版本改为Debug
常用的快捷键
F5
启动调试,经常用来直接跳到下一个断点处
F9
创建和取消断点
断点的重要作用,可以在程序任何位置设置断点
这样就可以使程序在想要的位置随意停止执行,继而一步步的操作下去
F10
逐过程,通常用来处理一个过程,一个过程可以是一次函数的调用,或者是一条语句
F11
逐语句,就是每次执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最常用的)
CTRL+F5
开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用
链接: 更多快捷键点这里
调试时查看程序当前的信息
- 查看临时变量的值
-----------------(监视用的最多)
可以查找出很多信息,比如堆栈,寄存器等
多多动手,尝试调试,才能有进步
- 一定要熟练掌握调试技巧
- 初学者80%的时间在写代码,20%的时间在调试,但是一个程序员可能20%的时间在写代码,80%的时间在调试
- 博主所讲解的只是简单的调试技巧
以后可能会出现复杂的调试场景,多线程程序的调试等等 - 多多使用快捷键,提高效率
举一个经典例子
#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("死循环了\n");
}
return 0;
}
如何写出好(易于调试)的代码
优秀的代码
- 代码运行正常
- bug很少
- 效率高
- 可读性高
- 可维护性高
- 注释清晰
- 文档齐全
常见的coding(编码)技巧:
- 1.使用assert
- 2.尽量使用const
- 3.养成良好的编码风格
- 4.添加必要的注释
- 5.避免编码的陷阱
那const是个什么玩意儿呢?
被const修饰的变量称为常变量—>不能被修改(除了通过地址修改)
举例:
- 直接修改
#include <stdio.h>
int main()
{
const int i = 11;
i = 20;
printf("%d ", i);
return 0;
}
直接报错
- 通过地址修改
#include <stdio.h>
int main()
{
const int i = 11;
int* p = &i;
*p = 20;
printf("%d ", i);
return 0;
}
那const修饰指针呢?
const放在*左边
- 1
const int* p = &i;
- 2
int const* p = &i;
含义: p指向的对象不能通过p来改变,但是p变量本身的值是可以改变的
举例:
#include <stdio.h>
int main()
{
const int i = 11;
int n = 100;
const int* p = &i;
*p = 20; // err
p = &n; //ok
printf("%d ", i);
return 0;
}
const放在*右边
int* const p = &i;
含义: p指向的对象可以通过p来改变,但是不能修改p本身的值
举例:
#include <stdio.h>
int main()
{
const int i = 11;
int n = 100;
int* const p = &i;
*p = 0; //ok
p = &n; // err
printf("%d ", i);
return 0;
}
*的左右都放上const,则铁定无法更改了
对const的通俗生活中举例
例子:
m是女孩子的男朋友----------------------------------- n是另一位喜欢女孩子的蓝孩子
她男朋友只有10块钱了,但是 n却有100块钱
女孩想吃牛肉面(10块钱),男朋友如果买的话,兜兜里就比脸还干净了
- 女孩子(const在*前面):男朋友不给买,就去找那一位蓝孩子,让他买
- 女孩子(const在*后面):男朋友说,😤我给你买,但是你不能去找那一个蓝孩子
- 如果两边都加上const,那就什么都吃不到咯
assert的理解
assert()的使用需要引用头文件
#include <assert.h>
int main()
{
assert(a);
return 0;
}
其中,当a=0,即NULL,则为假,就会直接导致程序报错。
他的使用可以帮助我们来避免一些用户输入问题或者其他数据输入输出问题
编译常见的错误
- 编译型问题
双击打开错误信息(语法错误),进行分析判断–>改正 - 链接型问题
查看错误信息,找到报错位置,分析其中标识符,一般是标识符名不存在或者拼写错误
比如:未定义的函数被调用,函数名错误 - 运行时错误
可以运行,但并不是想要的结果
方法:借助调试(难搞咯)