一、调试是什么?有多重要?
所有发送的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有愧,就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺腾而上,这就是推理的途径。
1.1 调试是什么?
调试又称除错,是发现和减少计算机程序或者电子仪器设备中程序错误的一个过程。
1.2 调试的基本步骤
- 发现程序错误的存在
- 以隔离、消除等方式对错误进行定位
- 确定错误产生的原因
- 提出纠正错误的解决方法
- 对程序错误予以改正,重新测试
1.3 Debug和Release的介绍
Debug通常称为调试版本,他包含调试信息,并且不作任何优化,便于程序员调试程序
Release称为发布版本,他往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好的使用
二、Windows环境调试介绍
最常用的几个快捷键:
F5:启动调试,经常用来直接跳到下一个断点处
F9:创建断点和取消断点
断点的重要作用:可以在程序的任意位置设置断点。这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去
F10:逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句
F11:逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进行函数内部
三、如何写出好(易于调试)的代码
3.1 优秀的代码
- 代码运行很正常
- bug很少
- 效率高
- 可读性高
- 可维护性高
- 注释清晰
- 文档齐全
常见的coding技巧
- 使用assert
- 尽量使用const
- 养成良好的编码风格
- 添加必要的注释
- 避免编码的陷阱
3.2 模拟实现strcpy
char* strcpy(char* dst, const char* src)
{
char* cp = dst;
assert(dst && src);
while (*cp++ = *src++)
;
return dst;
}
const 修饰指针变量的时候:
const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身的内容可以改变。
const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容可以通过指针改变。
模拟实现一个strlen函数
size_t strlen(char* src)
{
assert(src);
int cnt = 0;
while (*src)
{
src++;
cnt++;
}
return cnt;
}
四、编程常见的错误
编译性错误
编译性错误是在程序编译阶段发生的错误,它们会阻止程序的编译。常见的编译性错误包括:
- 语法错误:例如拼写错误、缺少分号、括号不匹配等。
- 类型错误:例如将一个整数赋值给一个字符串变量。
- 变量未声明:使用未声明的变量。
- 函数签名不匹配:函数的返回类型或参数类型与声明不匹配。
链接性错误
链接性错误通常在编译完成后,在将代码和库文件链接成可执行程序时发生。常见的链接性错误包括:
- 缺少库文件:程序使用了某个库或函数,但链接器找不到相应的库文件。
- 多重定义:同一个符号(例如函数或变量)在多个源文件中定义,导致链接器无法确定哪个定义是正确的。
- 未定义的符号:调用了一个函数或使用了一个变量,但是链接器在程序中找不到它的定义。
运行时错误
运行时错误是在程序运行时发生的错误,通常由程序的逻辑或外部环境因素引起。常见的运行时错误包括:
- 空指针引用:访问一个空指针或未初始化的指针。
- 数组越界:访问数组中不存在的元素。
- 除以零:在计算中除以零。
- 内存泄漏:动态分配内存后未正确释放,导致内存资源浪费。
- 死循环:由于程序逻辑错误导致无限循环。