学习笔记 | VS调试实用技巧

66 阅读4分钟

什么是Bug?什么是调试?Debug是什么?Release是什么?

对于IT人士,这些应该是已经记录在骨子里了,这里不在叙述。

今天主要学习VS的调试。

本来应该是写扫雷游戏,不过基于最近比较忙,自己也是没有完整的写出来整个逻辑,而且写出来也并不是我们想象中那种基于图形化可以用鼠标点击的那种,所以想着后面学完Window相关接口在做一个完整的扫雷。 正所谓世上无难事,只要肯放弃。

不过在写代码的时候对于调试不熟悉,确实很痛苦,这也是我决定先学习一下调试的原因。

调试

环境:

image-20231222192115673

调试常用快捷键:

  • F9:创建断点和取消断点,可以设置条件断点。
  • F5:启动调试,配合F9使用,注意这里是执行逻辑的下一个断点。
  • F10:逐过程,碰到函数直接执行函数,并返回函数结果,继续下一行。
  • F11:逐语句,可以跳到函数中(之前写扫雷,就是不会如何调试函数,吃了大亏!!!)。
  • CTRL + F5:直接执行所有程序。

VS更多快捷键了解:blog.csdn.net/mrlisky/art…

F9断点可以设置条件断点,比如某个循环需要执行1000次,我们想从501次开始观察,可以如下操作

image-20231222193244703

image-20231222193315300

此时如果按下F5,会直接跳过前面的500次循环,直接从501次开始执行。

监视和内存观察

监视

示例代码:

#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;
}

开始调试:

1、Debug模式,按F10

image-20231222192542866

一定要开始调试之后,才可以看到调试窗口!!!

2、调试 --> 窗口 --> 监视 --> 4个监视窗口(任选其一)

image-20231222192752213

3、按F10,逐语句调试,写上需要观察的变量。

image-20231222192929294

4、不仅是变量,表达式及内存地址都可以调试

image-20231222193034320

内存

&变量只是打印变量的地址,如果想查看内存地址及内存中的数据,可以通过 调试 --> 窗口 --> 内存

image-20231222193727453

可设置一行数据中显示几列

image-20231222193834533

第一部分为内存地址,第二部分为数据(16进制显示),第三部分为数据解析

image-20231222194006449

可输入arr,&i等

image-20231222194200860

除此之外,在调试的窗⼝中还有:⾃动窗⼝,局部变量,反汇编、寄存器等窗⼝。

调试举例1

求1!+2!+3!+4!+...10!的和,请看下⾯的代码:

为了方便计算预期,先求1 到 3 阶乘的和:1 + 1*2 + 1*2*3 = 9

预期结果应该是 9

#include <stdio.h>
​
int main()
{
    int n = 0;
    int i = 1;
    int sum = 0;
    int ret = 1;
    for (n = 1; n <= 3; n++)
    {
        for (i = 1; i <= n; i++)
        {
            ret *= i;
        }
        sum += ret;
    }
    printf("%d\n", sum);
    return 0;
}

执行结果

image-20231222194649426

有BUG。。。

进入调试模式:

image-20231222194834173

n=3 i = 3时,ret为12。因为我们把ret变量定义在main函数内,是次函数内范围最大的局部变量。

将ret函数在函数内定义后重新执行。

image-20231222195041030

执行结果符合预期。

调试举例2

环境:VS2022、X86、Debug.

#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;
}

首先第一眼看到数组越界了,所以会报数组越界的错误么?

执行如下:

image-20231222195306701

并没有报想象中的数组越界错误,而是进入了死循环。

必死不得其解!!进入调试模式:

image-20231222195516866

image-20231222195532657

继续执行,i 被赋值为 0 ,<=12 条件成立,如此进入了死循环。为什么 i 可以被重置为0 ?

继续查看i与arr[12]的内存地址

image-20231222200543236

他俩地址是一样的。

内存布局图如下:

image-20231222200702491

栈区内存由高到低分配,数组随着下标的增长,地址是由低到高;因为编译器的不同,i 与 arr数组差了2个地址(4个字节,正好是int分配的单位),所以当arr越界时,可能会跟 i 的地址重合。

那为什么没有报数组越界报错呢?因为执行完才会报错数组越界,这里先进入了死循环,代码没有时间报数组越界的错误!!!

据说这是一道面试题!!!

数组传参时,如何观察函数内部的数组内容?

arr,n:arr数组之后想看几个元素

二维数组默认只能看第一行,可以加上逗号n,可以看n行。

编程中常见的错误

  • 编译型错误

    • 基本都是语法错误,熟练之后相对简单。
  • 链接型错误

    • 大概率没有包含头文件。
  • 运行中错误

    • 程序执行结果与预期不符,基本要靠调试。