
调试对程序员来说是必不可少的,没人能保证一辈子写的代码一个bug都没有。所以学会调试,很重要。
没有手绘封面了,apple pencil丢了。。。
1. 调试 1.1 调试是什么?
1.2 怎么调试?调试(Debugging / Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序
错误的一个过程
- 发现错误
- 通过 隔离 、消除 等方式,定位错误
- 确定错误原因
- 思考解决办法
- 实现解决办法,对程序除错
- 重新测试
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优
的,以便用户很好地使用。
2. Windows下的调试 2.1 调试环境
2.2 调试快捷键在环境选项中选 Debug
F5
启动调试
常用于跳到下一个断点
F9
创建/取消断点
让程序在你希望的地方(至少是有意义的代码处)停下来
F10
逐过程
过程:一次函数调用,一条语句,都是一个过程
F11
逐语句
一次只执行一条语句,常用于进入函数内部
2.3 调试的重要部分:“监视”Ctrl + F5
不调试,直接执行程序
开始调试后,在“调试” – “窗口” 里,可以任意找到想监视的信息
3. 调试实例 3.1 例1
#include
int main()
{
int i = 0;
int n = 0;
int sum = 0;
int ret = 1;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
int j = 0;
for (j = 1; j <= i; j++)
{
ret *= j;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
结果:15
3! + 2! + 1! = 6+2+1 = 9
为什么得到15?
}
对 ret 的需求是每次存储 n 的阶乘,但是调试发现,ret 的值一直累加,正确代码应该是这样:
#include
int main()
{
int i = 0;
int n = 0;
int sum = 0;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
int ret = 1;
int j = 0;
for (j = 1; j <= i; j++)
{
ret *= j;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
3.2 例2调试过程中,时刻观察程序走向是不是和脑中构思好的一致
#include
int main()
{
int arr[10] = { 0 };
int i = 0;
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}
结果:死循环/报错(越界访问)
是的,这里越界访问了,但是根据 vs 的内存使用规则,越界访问的 arr[12] 刚好是 i ,每当程序要结束 , i 就又被赋成 0 ,导致死循环
vs在栈区使用空间,总是从高地址开始使用
vs数组的使用中,随着下标增加,地址由低到高
*静态区是右下角的方格,不知道怎么跑上去了 -_-
4. 如何写出好,还易于调试的代码? 4.1 优秀的代码
4.2 如何向优秀代码靠近?
- 运行正常
- bug很少
- 效率高
- 可读性高
- 可维护性高
- 注释明了
- 文档齐全
4.3 优秀代码示例(多向优秀代码学习)
- 使用assert(断言,我视它为保安)
- 尽量使用const
- 良好代码风格(适合的缩进,空格之类)
- 添加必要的注释(明了简洁)
- 避免代码的陷阱
#include
#include
//************
//= char* my_strcpy( dst , src ) - Copy one string over another
//
//= Purpose:
// Copies the string "src" into the spot
// specified by dest ; assumes enough room.
//
//= Entry:
// char* dst - string over which "src" is to be copied
// const char* src - string to be copied over "dst"
//
// = Exit:
// The address of "dst"
//**************
char* my_strcpy(char* dst, const char* src)
{
char* tool = dst;
//两个形参都不为NULL
assert(dst && src);
while (*tool++ = *src++)// ; = 0
{
//copy src over dst}
return
; dst}
int
main ()char
{
[ str1]= "Coding is funny!" ;char
[ str230]= 0 { } ;printf
("%s\n",my_strcpy (,str2) str1);return
0 ;}
#
4.4 const 的作用
const:赋予常量属性
看看例子(参考前辈的例子)
include//代码1
void
test1 ()int
{
= n 10 ;int
= m 20 ;int
* =p & ;n*
=p 20 ;//ok?=
p & ;m//ok? }
void
test2 ()//代码2
{
int
= n 10 ;int
= m 20 ;const
int *= p & ;n*
=p 20 ;//ok?=
p & ;m//ok? }
void
test3 ()int
{
= n 10 ;int
= m 20 ;int
* const= p & ;n*
=p 20 ;//ok? =
p & ;m//ok? }
int
main ()//测试无cosnt的
{
test1
();//测试const放在*的左边
test2
();//测试const放在*的右边
test3
();return
0 ;}
总结:就是看 const 在谁的左边
- 在 * 左边,就是修饰指针变量指向的内容:
指针指向的值被赋予常量属性- 在 * 右边,就是修饰指针变量:
指针变量里的地址被赋予常量属性
5. 编程常见错误 5.1 编译型错误
5.2 链接型错误多是语法问题,双击错误信息,根据错误信息修正即可
5.3 运行时错误多是 标识符不存在 、 拼写错误 、 没有声明
5.4 通向 “无bug” 的捷径逐步调试,细心对照:“是否和脑中构思的相同?”
不断积累排错经验,两点之间线段最短,脚踏实地就是最快的捷径
今天的分享就到这里
培根的blog,不断进步
:粉丝、阅读量不是初衷,写博客是为了倒逼自己输出,提升自己,不浮躁,不虚荣
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)