【07 vs调试技巧】

目录

  1. 什么是bug?
  2. 什么是调试?
  3. debug和release
  4. vs调试快捷键
  5. 监视和内存观察
  6. 调试举例1
  7. 调试举例2
  8. 调试举例3: 扫雷
  9. 编程常见错误归类

1. 什么是bug

 bug本意昆虫或虫子,现在一般指电脑系统或程序中,隐藏着一些未被发现的问题和缺陷,简称程序漏洞
 bug创始人格蕾丝·赫伯,继电器停止了工作,发现触点间有一只飞蛾,所以用“bug”来表示程序中的错误

2. 什么是调试

 发现程序中存在问题,下一步就是找到并修复问题,这个过程叫调试,debug,消灭bug的意思

3. debug和release

在这里插入图片描述
vs上有两个选项,分别是debug和release
debug通常称为调试版本:包含调试信息,不做任何优化,在编写的时候,如果需要经常调试代码,选择这个选项
release称为发布版本:进行了各种优化,大小和速度都是最优的。在最后交付使用的时候编译为这个版本,无需包含调试信息
在这里插入图片描述
对比两次生成的可执行程序,release明显更小

4. 调试快捷键

调试最常用的几个快捷键:
F9: 创建断点和取消断点
 断点可以在任何位置设置,程序执行到这里会暂停下来,接下来可以按F10,F11等快捷键观察细节
条件断点: 满足这个条件才执行断点
 在断点处右键选择条件,输入条件内容

在这里插入图片描述在这里插入图片描述

F5: 启动调试,经常用来直接跳转到下一个断点处,一般和F9配合使用
F10: 逐过程,处理过程,一个过程可以是一个函数和一个语句
F11: 逐语句,处理一条语句,遇到函数时可以进入内部,观察函数细节
SHIFT+F11: 直接跳出,可跳出当前函数,到调用前下一条语句
CRTL+F5: 开始执行不调试,程序直接运行不会断下来
如果调试过程无法结束,可点击红色方块强制结束:
在这里插入图片描述

更多快捷键: http://blog.csdn.net/mrlisky/article/details/72622009

5. 监视和内存观察

在调试过程中,怎么观察变量的值呢?如下列代码:

include <stdio.h>
int main()
{
	 int arr[10] = { 0 };
	 int num = 100;
	 char c = 'w';
	 int i = 0;
	 for (i = 0; i < 10; i++)
	 {
		 arr[i] = i;
	 }
 return 0;
}

5.1 监视窗口

调试模式下依次点开 调试→窗口→监视→监视1,并将窗口拖动到方便观察的位置
在这里插入图片描述

在监视窗口中输入对应变量,就能查看当前值,数组可以点开查看每一个数据
在这里插入图片描述

5.2 内存窗口

调试模式下依次点开 调试→窗口→内存→内存1,并将窗口拖动到方便观察的位置
在这里插入图片描述
在这里插入图片描述
计算机中数据是二进制存储的,内存窗口中数据是十六进制显示的,两个十六进制是一个字节,上面的两个00为1个字节

除此之外,还有自动窗口、局部变量、反汇编、寄存器等

6. 调试举例1

调试找出下列代码的问题:

1!+2!+....10!的和

//写⼀个代码求n的阶乘
int n = 0;
scanf("%d", &n);
int i = 1;
int ret = 1;
for (i = 1; i <= n; i++)
{
	ret *= i;
}

printf("%d\n", ret);
//如果n分别是1,2,3,4,5...10,求出每个数的阶乘,再求和就好了
//在上⾯的代码上改造
int n = 0;
int i = 1;
int sum = 0;
for (n = 1; n <= 10; n++)
{
	for (i = 1; i <= n; i++)
	{
		ret *= i;
	}
	sum += ret;
}
printf("%d\n", sum);

将i值改为3,先求3的阶乘和,发现结果是15,不是9,所以对3的阶乘进行调试,在for循环内部找一断点
在这里插入图片描述
F5启动调试,输入n,sum,ret的值进行观察。然后单步执行到第二次外层for
在这里插入图片描述

此时算完1的阶乘和,1的阶乘等于1,sum表示阶乘和=1,没问题,继续执行到下一次for
在这里插入图片描述

2的阶乘是2,和是加上1的阶乘等于3,继续下一轮
在这里插入图片描述

3的阶乘计算为12,计算错误,为了进一步观察,将n的条件断点设为3,重新断一次
在这里插入图片描述

在这里插入图片描述
n的阶乘需要计算1的阶乘和2的阶乘,这里在计算1的阶乘时还没执行,ret值就已经是2了,所以问题在于ret值没有初始化,保留的还是上次计算的2的阶乘值

解决:
在每次计算阶乘前对ret都初始化为1
在这里插入图片描述在这里插入图片描述
于是3的阶乘是9,其他阶乘也计算无误了。调试完成,右键点击断点删除或光标停在代码行按F9删除断点

7. 调试举例2

vs中不做优化,下面代码的执行结果是:

#include <stdio.h>
int main()
{
 int i = 0;
 int arr[10] = {0};
 for(i=0; i<=12; i++)
 {
 arr[i] = 0;
 printf("hehe\n");
 }
 return 0;
}

运行后发现死循环了,调试一下:
for循环内部下一个断点

在这里插入图片描述

观察i和arr的值
在这里插入图片描述

在第13次循环时,i值为12,当执行arr[i]=0这条代码后,i值变为了0。数组只有10项,那么arr[12]=0为什么会让i值变为0,此时重新调试到此处打开内存窗口
在这里插入图片描述

地址处输入arr,回车自动转换跳到地址,红色框为10个数组的部分
在这里插入图片描述

监视窗口输入取地址arr[12]和i的地址,在内存窗口中观测到这两个为同一地址,值都是12
在这里插入图片描述
由于i和arr[12]是同一个地址,所以给arr[12]赋值时,i的值也自动变为了0,所以循环继续从0开始,跳不出去

根据以上可深入分析:
 内存中数组是连续存放的,局部变量存放在栈区,栈区的地址是从高地址往低地址存放,所以i先申请的,先存放在高地址,arr后申请,存放在较低的地址,然后随着下标不断往高地址放。刚好越界后隔了两个整形就是i的地址,两个变量中间空多少是由编译器决定的
在这里插入图片描述

8. 调试举例3:扫雷

如果是一个比较复杂的项目,该怎么调试呢?这里用上一章的扫雷举例

  • 首先理清项目执行的主逻辑,找到有问题的函数,在关键的地方下断点, 用相应的选项断到此处
  • 需要观察什么变量就在监视窗口中输入,一步步观察变化

如排查可能是SetMine函数有问题,可在内部有问题的代码前下断点,开始调试,选择1,开始游戏,运行到断点:
在这里插入图片描述

监视窗口输入观察的x,y和mine[x][y]
在这里插入图片描述
一步步不断运行

9. 编程常见错误归类

9.1 编译型错误

一般是语法错误,错误信息中可以看到错误内容,双击可跳到出错的位置
在这里插入图片描述

9.2 链接型错误

看错误提示,找错误信息的标识符,一般是下面几点:

  • 标识符名不存在
  • 拼写错误
  • 头文件没包含
  • 引用的库不存在
    在这里插入图片描述

9.3 运行错误

一般无具体情况,千变万化,调试解决该问题

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值