一 ,什么是Bug?
二 ,什么是调试?
当我们运行程序的时候,发现可以运行但是结果并不正确(或者说与自己像的并不一样),这时候我们就需要找到问题,然后解决问题!而这个找问题的过程就是调试,英文叫debug(消灭 bug)的意思。
三 ,debug 和 release
Debug是调试版本, 包含调试信息,不做任何优化,方便程序员进行调试。
Release是发布版本,进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户更好的使用。无需包含调试信息!
四 ,VS调试快捷键
注意:调试需要在Debug环境下进行
1.F9 :创建断点和取消断点
2.F5 :启动调试,如果有设置断点,直接跳转到断点处执行
3.ctrl + F5 :开始执行不调试
4.F10 :逐过程,通常用在处理一个过程,一个过程可以是一次函数调用,或者是一条语句 。
5.F11 :逐语句,每次都执行一条语句,与F10不同的是,可以使我们执行逻辑进入到函数内部。
注意:F5与F9搭配使用跳的是执行逻辑上的断点,并不是物理逻辑上的断点!
五 ,监视和内存观察
如果我们想观察代打在执行的过程中,上下文环境中的变量值,有哪些方法?
以下代码为案例:
#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 监视观察
5.2 内存观察
在打开内存窗⼝后,要在地址栏输⼊:arr,&num,&c,这类地址,就能观察到该地址处的数据。除此之外,在调试的窗口中还有:自动窗⼝,局部变量,反汇编、寄存器等窗⼝,自行验证使用一下。
六 ,案例分析
1.求 1!+2!+3!+4!+...10! 的和
//求n的阶乘
//5! = 1*2*3*4*5
//4! = 1*2*3*4
//3! = 1*2*3
所以我们的思路可以是,先求得 //⼀个代码求n的阶乘
#include <stdio.h>
//写⼀个代码求n的阶乘
int main()
{
int n = 0;
scanf("%d", &n);
int i = 1;
int ret = 1;
for(i=1; i<=n; i++)
{
ret *= i;
}
printf("%d\n", ret);
return 0;
}
然后再求每个阶乘的和,可运行以下代码来进行调试,并找出BUG
int main()
{
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);
return 0;
}
在进行调试后,我们可以发现,在走完ret * =i 的运算时,我们的ret并没有回到1,而是保留了上一个阶乘的乘积,所以我们需要加上一条语句 ret = 1;
2. 在VS2022、X86、Debug 的环境下,编译器不做任何优化的话,下⾯代码执行的结果是啥?
#include <stdio.h>
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;
}
我们运行完之后,发现程序 进入了死循环,可以尝试调试一下,试着看是什么原因:
我们发现,程序存在数组越界,非法访问内存,可能会导致程序崩溃;
1. 我们的局部变量是再栈区中存放的,而栈区内存的使用习惯是:先使用高地址处的空间,然后再使用低地址处的空间
2.数组在内存中存放:随着下标的增长,地址是由低到高变化的。
所以随着数组下标的增长,往后越界就有可能覆盖到 i ,这样就有可能造成循环!