云边有个稻草人-CSDN博客
作为一名预备程序员,调试真是至关重要,今天我们共同学习如何在VS里面如何调试来解决程序中的问题。
依旧是认真地完成了本篇博客。

目录
1. 什么是bug?
2. 什么是调试?
3. Debug和Release
4. VS调试快捷键
4.1 环境准备
4.2 调试快捷键
5. 监视和内存管理
5.1 监视
5.2 内存管理
6. 调试举例1
7.调试举例2
【VS2022,Debug,X86】
【Debug,X64】
【Release,X86】
【一道经典面试题】
8.调试举例3:扫雷
演示1
演示2
9. 编程常见错误归类
9.1 编译型错误
9.2 链接型错误
9.3 运行时错误
正文开始——
1. 什么是bug?
bug本意是“昆⾍”或“⾍⼦”,现在⼀般是指在
电脑系统或程序中,隐藏着的⼀些未被发现的缺陷或问题
,简称
程序漏洞。
“Bug” 的创始⼈格蕾丝·赫柏(Grace Murray Hopper),她是⼀位为美国海军⼯作的电脑专家,1947年9⽉9⽇,格蕾丝·赫柏对Harvard Mark II设置好17000个继电器进⾏编程后,技术⼈员正在进⾏整机运⾏时,它突然停⽌了⼯作。于是他们爬上去找原因,发现这台巨⼤的计算机内部⼀组继电器的触点之间有⼀只⻜蛾,这显然是由于⻜蛾受光和热的吸引,⻜到了触点上,然后被⾼电压击死。所以在报告中,赫柏⽤胶条贴上⻜蛾,并把“bug”来表⽰“⼀个在电脑程序⾥的错误”,“Bug”这个说法⼀直沿⽤到今天。

2. 什么是调试?
当我们发现程序中存在的问题的时候,那下⼀步就是找到问题,并修复问题。
这个
找问题的过程叫称为
调试
,英⽂叫debug(消灭bug的意思)。
调试⼀个程序,⾸先是承认出现了问题,然后通过各种⼿段去定位问题的位置,可能是逐过程的调试,也可能是隔离和屏蔽代码的⽅式,找到问题所的位置,然后确定错误产⽣的原因,再修复代码,重新测试。
3. Debug和Release

在VS上编写代码的时候,就能看到有
debug
和
release
两个选项,分别是什么意思呢?
Debug 通常称为调试版本
,它包含调试信息,并且不作任何优化,便于程序员调试程序;程序员在写代码的时候,需要经常性的调试代码,就将这⾥设置为 debug
,这样编译产⽣的是debug 版本的可执⾏程序,其中包含调试信息,是可以直接调试的。
Release 称为发布版本
,它往往是进⾏了各种优化,使得程序在代码⼤⼩和运⾏速度上都是最优的,以便⽤⼾很好地使⽤。当程序员写完代码,测试再对程序进⾏测试,直到程序的质量符合交付给⽤⼾使⽤的标准,这个时候就会设置为 release
,编译产⽣的就是
release
版本的可执⾏程序,这个版本是⽤⼾使⽤的,⽆需包含调试信息等。

对⽐可以看到从同⼀段代码,编译⽣成的可执⾏⽂件的⼤⼩,release版本明显要⼩,⽽debug版本明显⼤。
4. VS调试快捷键
程序员该如何调试代码呢?
4.1 环境准备
⾸先是环境的准备,需要⼀个
⽀持调试的开发环境
,我们使⽤VS,应该把VS上设置为Debug,如图:

4.2 调试快捷键
【常用——要求熟练掌握】接下来我们用简单的代码来进行演示一下
F9:
创建断点和取消断点(我的电脑需要配合Fn),注意断点不是单独使用的,是要搭配使用的。
断点的作用
是可以在程序的任意位置设置断点,打上断点就可以使得程序执⾏到想要的位置暂停执⾏,接下来我们就可以使⽤F10,F11这些快捷键,观察代码的执⾏细节。
F5:
启动调试,经常⽤来直接跳到下⼀个断点处,⼀般是和F9配合使⽤。
就是说我们想要直接到第13行,如果按F10就是一行一行的执行,还要进入到for循环里面一步一步的执行就比较费劲,这时打了断点之后用F5直接跳到断点处就很方便。
【注意情况1】
【注意情况2】
但是当我们再按一次F5程序会运行到哪里呢?第二个断点处还是。。。看效果

执行到下面的断点情况亦是如此——所以注意: F5是让程序执行到运行逻辑上的下一个断点处,而不是物理意义上的断点处。
【注意情况3】
如果我们在第一个循环里面想要直接跳到 i==5 时的情况,我们可以使用条件断点
条件断点:满⾜这个条件,才触发断点



F10:逐过程,通常⽤来处理⼀个过程,⼀个过程可以是⼀次函数调⽤,或者是⼀条语句。

F11:
逐语句
,就是每次都执⾏⼀条语句,但是这个快捷键可以使我们的执⾏逻辑进⼊函数内部。在函数调⽤的地⽅,想进⼊函数观察细节,必须使⽤F11,如果使⽤F10,直接完成函数调⽤。
所以说对于普通的语句F10和F11效果是一样的,但是对于函数,F11能进入到函数内部,F10不能!

【总结】
F5和F9是帮助我们快速到达我们想要到的地方,F10和F11是帮助我们到达地方后观察程序内部的运行情况的。
CTRL + F5:
开始执⾏不调试,如果你想让程序直接运⾏起来⽽不调试就可以直接使⽤。
(为什么点击F5也可以直接完成运行呢?因为F5是用来运行到下一个断点处的,但是整个程序都运行结束了都没有发现断点)
上面是我们很常用的快捷键,下面还有很多快捷键,我们平时应该多用才能提升我们写代码的速度,多用才能记住!
VS快捷键大全-CSDN博客(更多详情见这里,因VS版本不同可能会有点偏差)
5. 监视和内存管理
5.1 监视
在调试的过程中我们,如果要观察代码执⾏过程中,上下⽂环境中的变量的值,有哪些⽅法呢?
这些观察的前提条件
⼀定是开始调试(按F10或F11都可以)后观察
,⽐如:
监视窗口哪里可以手动打开呢?
开始调试后,在菜单栏中【调试】->【窗⼝】->【监视】,打开任意⼀个监视窗⼝,输⼊想要观察的对象就⾏。

5.2 内存管理
如果监视窗⼝看的不够仔细,也是可以观察变量在内存中的存储情况,还是在【调试】->【窗⼝】-> 【内存】,打开内存窗⼝:
在打开内存窗⼝后,要在地址栏输⼊:arr,&num,&c,这类地址,就能观察到该地址处的数据。

内存里面的数据以16进制的形式展现,一个16进制位相当于4个2进制位,2个16进制位相当于8个二进制位也就是1个字节,所以我们看到了一个数据是4个字节对应1个整型。



除此之外,在调试的窗⼝中还有:⾃动窗⼝,局部变量,反汇编、寄存器等窗⼝,⾃⾏验证使⽤⼀下。
6. 调试举例1
求
1!+2!+3!+4!+...10!
的和,请看下⾯的代码:


代码的优化:

7.调试举例2
【VS2022,Debug,X86】
在VS2022、X86、Debug
的环境下,编译器不做任何优化的话,下⾯代码执⾏的结果是啥?
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("hehe\n");
}
return 0;
}
程序运⾏,死循环了,调试看看为什么?




我们可以看到,在前期的时候 arr[12] 里面的值随着 i 的变化而变化,后面arr[12] = 0,i 的值变成了0,可见它们确实共用一块内存空间。
我们取地址验证一下:

解释:
【注意】以下的解释和上面的演示都是在VS2022,X86,Debug环境下,这跟环境关系很大。

【Debug,X64】
同样的Debug版本,X64就会报错而不是死循环
arr 创建在 i 的上面,arr 越界访问不会覆盖到 i,就不会出现死循环。但是其主要的原因还是因为arr越界了而不是改变环境的问题


【Release,X86】
压根儿不会出现报错了

【一道经典面试题】

8.调试举例3:扫雷
如果一个代码稍微复杂,那怎么调试呢?
这里我们上手调试一下扫雷的代码。
演示1
重点:在数组传参,调试进⼊函数,如何在监视窗⼝观察数组的内容: 数组名,n 的形式


真心告诫
调试过程中,要做到中有数,也就是程序员自己心里要清晰的知道希望代码怎么执行,然后再去看代码有没有按照我们预定的路线在执⾏。
调试是需要反复去动⼿练习的,调试是可以增加程序员对代码的理解和掌控的,掌握了调试的能力,就能看到本质,就像能给程序做B超⼀样,对程序内部⼀览无余。
演示2
在函数内部打断点,快速跳转到函数,可以在函数调用时打断点,也可以在函数内部打断点实现直接跳转。

9. 编程常见错误归类
test.c -> 编译 -> 链接 -> test.exe的可执行程序
9.1 编译型错误
编译型错误⼀般都是
语法错误
,这类错误⼀般看错误信息就能找到⼀些蛛丝⻢迹的,
双击错误信息
也能初步的跳转到代码错误的地⽅或者附近。编译错误,随着语⾔的熟练掌握,会越来越少,也容易解决。

9.2 链接型错误
看错误提⽰信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。⼀般是因为
- 标识符名不存在
-
拼写错误
-
头文件没包含
-
引用的库不存在
一般看到无法解析的外部符号就是链接型错误,这种错误我们无法通过双击如编译型错误一样在程序中实现定位。


9.3 运行时错误
运⾏时错误,是千变万化的,需要借助调试,逐步定位问题,今天学的调试解决的是运⾏时问题。当我们遇见运行时错误的时候,我们要尝试自己调试,在调试的过程中我们就是在尝试自己发现问题所在然后尝试解决问题,而且能增加我们对代码的掌控力。
告诉我自己遇到问题一定要尝试调试,尝试调试!!!
完——(休息一下)
~ 嗨起来 ~
————————————————《自娱自乐》————————————————
自娱自乐_金志文_高音质在线试听_自娱自乐歌词|歌曲下载_酷狗音乐
(菜鸡的我听着这首歌又兴奋起来了)

至此结束——
我是云边有个稻草人
期待与你的下一次相遇!