调试解决的就是代码的运行时错误
关于调试的一些快捷键
F5
启动调试,经常用来直接调到下一个断点处。 (F5与F9通常配合使用,用于跳过不需要调试的过程,节省时间,提高效率)
F9
创建断点和取消断点。 断点的重要作用:可以在程序的任意位置设置断点,这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
F10
逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。(按一下执行一步)
F11
逐语句,每次都执行一次语句,大部分情况下与F10的效果相同,但 F11最大的作用是可以使我们的执行逻辑进入函数内部。
CTRL + F5
开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。
fn -- 辅助功能键 (如果上述快捷键没反应,可以在前面加上辅助键,或者选择关闭fn这个辅助功能键)
调试时查看程序当前的信息
按下F10调试起来之后我们才能看到窗口里面可以观察的一些信息
断点窗口
可以直观查看断点所在的文件和行数
监视窗口
任意设置添加想要观察的程序中的信息,即想要监视的项。(合理的情况下) 此窗口用得最多
自动窗口
编译器自动根据程序运行来添加要监视的项(随时可能会发生变化) 一般情况下使用监视窗口而非自动窗口
局部变量窗口
自动监视程序执行过程中,上下文环境中的局部变量
内存窗口
内存窗口中有地址区、内存数据区和翻译文本区。其中内存数据展示出来的是十六进制的形式,但实际是用二进制来存储的。 该窗口可以看做为(更细致的)监视窗口,需要观察时对某一变量取地址即可。
反汇编
可以观察到当前编程语言翻译为汇编代码的相关的内容
寄存器窗口
观察寄存器的情况(寄存器会随时发生变化)
调用堆栈窗口
该窗口可以反馈函数的调用逻辑
条件断点
断点可以设置条件。例如:想要在一个循环中的第n次终止,可以右击断点,并设置相关的条件,就可以不用通过手动点击F10来进行这个过程了。
调试案例
#include <stdio.h> int main() { int i = 0, arr[10] = { 0,1,2,3,4,5,6,7,8,9 }; for (i = 0; i <= 12; i++) { arr[i] = 0; printf("hahaha\n"); } return 0; }
上面这段代码运行的结果为死循环,调试判断其原因。
最终我们发现,i的地址和arr[12]的地址相同,故而赋值到arr[12]的时候将i也同样赋值为0
这样的巧合是因为:
一、i和arr是局部变量, 局部变量 是放在 栈区上 的 栈区内存的使用习惯是: 先使用高地址空间,再使用低地址空间。
二、数组随着下标的增长地址是 由低到高变化 的
假设下方是一个栈区内存:
此处的i先占用了高地址的内存空间,而后数组建立,逐渐由低地址向高地址开始占用内存空间。
直到arr与i重合,才导致了之前出现了死循环的情况。
也正是因为其一直处于死循环的状态,才没有弹出数组越界的错误的提示。