Visual Studio 2022 调试指南:如何处理编译正确但运行结果错误的问题

一、调试是什么?有多重要?

调试(debug)又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程

二、debug和release的介绍

Debug通常称为调试版本,它包含调试信息,并且不作任何优化,便于调试
Release被称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好的使用

三、windows环境调试介绍

①将环境改为Debug

②学会快捷键

F5:

启动调试,经常用来直接跳到下一个断点处
例如:如果在48行和69行设置了两个断点,按F5后程序跳到48行,再按一次,程序跳到69行
特例:在循环中打断点:
for(int i=0;i<10;i++)
{
    k+=i;//如果在这行打了断点,按F5后就不会跳到下一个断点
}
F9:
创建断点和取消断点
断点的重要作用可以在程序的任意位置设置断点,如果前面没有输入输出操作,程序将直接运行到断点处打了多个断点,可以在调试窗口-断点中观察自己的断点在哪一行

如果想要在断点处设置条件,只有满足条件才会触发断点

右击断点-条件

F10:逐过程,可以是一次函数调用可是一条语句(遇到函数直接跳过)

F11:逐语句,跟F10不同的是,可以进入函数内部(遇到函数会进去函数内部)

ctrl+F5:开始执行不调试,就算打了断点也不会停

在程序执行过程中想要观察程序的上下文的环境的相关数据(例如定义了一个变量a,a在运行过程中的变化情况),在调试(运行)之后,点击窗口

重点:监视、调用堆栈、内存、反汇编、寄存器

监视:可自己添加删除自己想监控的元素

注:如果在函数中传入数组,这时候如果想监视这个数组,上面只会显示数组中的第一个元素,如果想要显示自定义的数组范围:数组名+,+范围,例:

内存:如果想要看a在内存里面的位置,在地址里面输入&a,回车就出现下面场景

如果要看arr,在地址里面输入&arr,回车

反汇编:观察代码翻译为汇编代码是什么样的

寄存器: 可以观察代码在运行中观察寄存器的值,当然如果你知道寄存器的名字,可以在监视中观察

调用堆栈:

在数据结构中:栈:先进后出  队列:先进先出

局部变量是放在内存中的栈区的

栈区的使用习惯是先试用高地址的空间再使用地地址的空间

四、如何写好(易于调试)的代码

常见的coding技巧 :

  1. 使用assert

  2. 尽量使用const

  3. 养成良好的编码风格

  4. 添加必要的注释

  5. 避免编码的陷阱

示范:
模拟实现库函数strcpy--字符串拷贝
将arr1的字符串拷贝到arr2中去
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
    char arr1[] = "hello";
    char arr2[20] = { 0 };
    strcpy(arr2, arr1);
    printf("%s", arr2);
    return 0;
}

自己写:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void my_strcpy(char* dest, char* src)
{
    while (*src != '\0')
    {
        *dest = *src;
        dest++;
        src++;
    }
    *dest = *src;//把\0拷贝过去
}
int main()
{
    char arr1[] = "hello";
    char arr2[20] = { 0 };
    my_strcpy(arr2, arr1);
    printf("%s", arr2);
    return 0;
}

这个代码可以发挥作用,但是不够好,接下来做一些优化

while (*dest++ = *src++)//只要src指向的内容不是0,循环就不会停止,即做到了拷贝又做到遇到\0停下来

        ;//改为后置++,先赋值后++  

断言:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
void my_strcpy(char* dest, char* src)
{
    
    assert(src != NULL||dest!=NULL);
    while (*dest++ = *src++)//只要src指向的内容不是0,循环就不会停止,即做到了拷贝又做到遇到\0停下来
        ;//改为后置++,先赋值后++
}
int main()
{
    char arr1[] = "hello";
    char arr2[20] = { 0 };
    my_strcpy(arr2, arr1);
    printf("%s", arr2);
    return 0;
}

if (src == NULL || dest == NULL)

    {

        return;

    }

  每次进入函数内部都要判断一次,如何更高效?用assert(需要包含头文件assert.h),里面可以放一个表达式,如果表达式的结构为假,就报错,如果为真啥事都不发生

但是在Release版本中优化掉了

const

const修饰指针变量的时候放在*左边时,修饰指针指向的内容,*p不能改但是p可以改(const int *p)

const修饰指针变量的时候放在*右边时,修饰的指针变量本身,*p能改但是p不可以改(int *const p)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值