Visual Studio实用调试技巧---让你成为高端的程序员

news2024/11/25 13:53:46

🍁 博客主页:江池俊的博客
💡代码仓库:江池俊的代码仓库
🎪 社区:GeekHub

🍁 如果觉得博主的文章还不错的话,请点赞👍收藏🌟 三连支持一下博主💞

文章目录

  • 一、 什么是bug?
  • 二、调试是什么?有多重要?
    • 🍁 调试的基本步骤
  • 三、Debug和Release版本的介绍。
  • 四、Windows环境调试介绍
    • 🍁常用快捷键
    • 🍁调试的时候查看程序当前信息
  • 五、调试实例
    • 🍁 实例1
    • 🍁 实例2
  • 六、如何写出好(易于调试)的代码
    • ``🍁assert的使用``
    • ``🍁空指针和野指针的危害``
    • ``🍁const的作用``
  • 七、编程常见的错误

一、 什么是bug?

在这里插入图片描述
第一次被发现的导致计算机错误的飞蛾,也是第一个计算机程序错误。
注:参考链接


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

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

🍁 调试的基本步骤

  1. 发现程序错误的存在
  2. 以隔离、消除等方式对错误进行定位
  3. 确定错误产生的原因
  4. 提出纠正错误的解决办法
  5. 对程序错误予以改正,重新测试

三、Debug和Release版本的介绍。

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

代码:

#include <stdio.h>
int main()
{
 char *p = "hello world.";
 printf("%s\n", p);
 return 0;
}

上述代码在Debug环境的结果展示:
在这里插入图片描述
上述代码在Release环境的结果展示:
在这里插入图片描述
Debug和Release反汇编展示对比:
在这里插入图片描述
所以我们说调试就是在Debug版本的环境中,找代码中潜伏的问题的一个过程。


四、Windows环境调试介绍

  • Debug为调试版本,一般在开发完成后发布工程前,调试代码都是在Debug模式下进行的。
  • Release版本是不能调试的,一般都是在Debug版本下调试的,Release版本一般编译器会进行大量的优化,删除无用的代码,指令的次序调整等,让其速度更快。

在这里插入图片描述
在环境中选择 debug 选项,才能使代码正常调试。

🍁常用快捷键

  • F5 --> 启动调试,经常用来直接跳到下一个断点处。一般不会单独使用,而是配合F9一起使用。
  • F9 --> 创建断点和取消断点。断点的重要作用:可以在程序的任意位置设置断点。这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
  • F10 --> 逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。(遇到函数直接执行完整个函数,不进入函数内部)
  • F11 --> 逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最 常用的)
  • CTRL + F5 --> 开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。
    想知道更多快捷键?点我

🍁调试的时候查看程序当前信息

1. 查看临时变量的值:在调试开始之后,用于观察变量的值。
监视窗口:
在这里插入图片描述

2. 查看内存信息:在调试开始之后,用于观察内存信息。
内存窗口:
在这里插入图片描述

3. 查看调用堆栈:通过调用堆栈,可以清晰的反应函数的调用关系以及当前调用所处的位置。
调用堆栈窗口:
在这里插入图片描述

4. 查看汇编信息:在调试开始之后,有两种方式转到汇编:
(1)第一种方式:右击鼠标,选择【转到反汇编】:
在这里插入图片描述

 (2)第二种方式:调试窗口找到反汇编

在这里插入图片描述

5. 查看寄存器信息:可以查看当前运行环境的寄存器的使用信息。
在这里插入图片描述

多多动手,尝试调试,才能有进步。

一定要熟练掌握调试技巧, 初学者可能80%的时间在写代码,20%的时间在调试。但是一个程序员可能20%的时间在写 程序,但是80%的时间在调试。


五、调试实例

🍁 实例1

实现代码:求 1!+2!+3! …+ n! ;不考虑溢出。
在这里插入图片描述代码改正:

#include<stdio.h>
int main()
{
	int i = 0;
	int sum = 0;//保存最终结果
	int n = 0;
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		int ret = 1;//保存n的阶乘
		int j = 0;
		for (j = 1; j <= i; j++)
		{
			ret *= j;
		}
		sum += ret;
	}
	printf("%d\n", sum);
	return 0;
}

🍁 实例2

在这里插入图片描述
注意:此代码非常依赖环境,在vs2022 debug版本x86环境下才是死循环的,而release版本下此代码会被优化,改变内存布局,不会死循环。
在这里插入图片描述


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

优秀代码的特点:

  1. 代码运行正常
  2. bug很少
  3. 效率高
  4. 可读性高
  5. 可维护性高
  6. 注释清晰
  7. 文档齐全

常见的coding技巧:

  1. 使用assert
  2. 尽量使用const
  3. 养成良好的编码风格
  4. 添加必要的注释
  5. 避免编码的陷阱。

🍁assert的使用

assert 函数是一种在代码中用于测试和调试的工具,它用于在运行时检查一个条件是否为真。如果条件为真,则 assert 什么也不做,程序继续执行。但如果条件为假,assert 会引发一个异常(通常是 AssertionError),中断程序的执行。
示例:

模拟实现库函数:strcpy

/*
库函数strcpy
1.描述
C 库函数 char *strcpy(char *dest, const char *src) 把 src 所指向的字符串复制到 dest。
需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。
2.声明
下面是 strcpy() 函数的声明。
char *strcpy(char *dest, const char *src)
3.参数
dest -- 指向用于存储复制内容的目标数组。
src -- 要复制的字符串。
4.返回值
该函数返回一个指向最终的目标字符串 dest 的指针。           */
char *my_strcpy(char * dst, const char * src)
{
        char * cp = dst;
        assert(dst && src);//断言,防止传进来的是空指针或野指针
        while( *cp++ = *src++ )
        { 
             ;
        }     /* Copy src over dst */
        return dst;
}

🍁空指针和野指针的危害

1.空指针(Null Pointer):

空指针是指不指向任何有效内存位置的指针,通常用空值(NULL)表示。空指针通常表示指针尚未初始化或不引用任何有效的内存。访问空指针通常会导致程序崩溃或未定义的行为。主要危害有:

  • 程序崩溃:访问空指针可能会导致程序直接崩溃,因为操作系统会捕获到这种无效的内存访问并终止程序。
  • 未定义行为:C语言标准规定对空指针的解引用是未定义行为,这意味着不同的编译器和平台可能会表现出不同的行为,包括奇怪的运行时行为和数据损坏。
  • 安全问题:攻击者可以利用空指针漏洞来执行恶意代码,从而造成系统的安全问题。

2.野指针(Dangling Pointer):
野指针是指在指针指向的内存位置被释放或无效后,仍然保持了该指针的值。在访问野指针时,可能会读取到无效的数据或者修改其他内存区域,导致未定义的行为。主要危害有:

  • 数据损坏: 野指针可能会导致数据损坏,因为程序可能会误用已经释放或者不再有效的内存位置。
  • 难以调试: 由于野指针可能导致未定义行为,程序可能会表现出奇怪的错误,这会使调试变得非常困难。

🍁const的作用

const修饰指针变量的时候:

  1. const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本身的内容可变。
#include <stdio.h>

int main() {
    int num = 5;
    const int* ptr = &num;  // const在*的左边,指针本身可以变,但是指向的内容不可变
    // *ptr = 10;  // 这里会产生编译错误,因为不能通过ptr修改num的值
    num = 10;  // 可以通过num直接修改值
    printf("num: %d\n", num);  // 输出:num: 10

    int another_num = 20;
    ptr = &another_num;  // 可以将ptr指向另一个整数

    return 0;
}

在上述示例中,ptr 是一个指向 const int 的指针,这意味着不能通过 ptr 来修改它指向的内容,但可以通过修改 num 的值来间接地修改指针所指向的内容。另外,可以改变 ptr 指向其他整数。

  1. const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指
    针指向的内容,可以通过指针改变。
#include <stdio.h>

int main() {
    int num = 5;
    int* const ptr = &num;  // const在*的右边,指针本身不可变,但是指向的内容可以改变
    *ptr = 10;  // 可以通过ptr修改num的值
    printf("num: %d\n", num);  // 输出:num: 10

    // 以下操作是不允许的,因为ptr已经被声明为const,不能指向其他内存
    //int another_num = 20;
    // ptr = &another_num;  // 编译错误

    return 0;
}

在上述示例中,ptr 是一个指向 num 的常量指针,这意味着不能通过 ptr 来改变它指向的位置,但可以通过 *ptr 来修改它指向的内容。


练习:

模拟实现一个strlen函数

#include <stdio.h>
int my_strlen(const char *str)
{
    int count = 0;
    assert(str != NULL);//断言,也可以写成 assert(str);
    while(*str)//判断字符串是否结束
   {
        count++;
        str++;
   }
    return count;
}
int main()
{
    const char* p = "abcdef";
    //测试
    int len = my_strlen(p);
    printf("len = %d\n", len);
    return 0;
}

七、编程常见的错误

  1. 编译型错误
  • 产生原因:编译型错误是在编译阶段发生的错误,通常是由于语法错误、类型错误、未定义的标识符等造成的。编译器无法正确解析代码,因此无法生成可执行文件。
  • 解决方法:仔细检查代码,确保语法正确、类型匹配,并确保使用的标识符在正确的作用域中定义。查看编译器的错误信息和警告,逐一修复问题。相对来说简单。
  1. 链接型错误
  • 产生原因:链接型错误发生在链接阶段,当编译器尝试将多个源文件组合成一个可执行文件时。常见的链接错误包括重复定义、未定义的符号等。
  • 解决方法:确保不同源文件中的函数和变量只有一次定义,避免重复定义。如果遇到未定义的符号错误,检查是否缺少某个库文件的链接,或者确保函数定义在正确的源文件中。一般是标识符名不存在或者拼写错误。
  1. 运行时错误
  • 产生原因:运行时错误发生在程序执行阶段,可能由于无效的内存访问、除以零、类型不匹配等引起。这些错误可能导致程序崩溃、产生未定义行为或者不正确的结果。
  • 解决方法:使用合理的错误处理机制来捕获和处理运行时错误。例如,对于可能导致除以零的情况,可以在执行之前进行条件检查。使用异常处理机制(例如C++ 中的 try-catch)来捕获异常情况并进行适当的处理。确保指针的正确初始化和检查,以避免空指针或野指针问题。要习惯借助调试,逐步定位问题。最难搞。

🔥今天的分享就到这里,如果觉得博主的文章还不错的话,请👍三连支持一下博主哦🤞
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/848341.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

链式二叉树统计结点个数的方法和bug

方法一&#xff1a; 分治&#xff1a;分而治之 int BTreeSize1(BTNode* root) {if (root NULL) return 0;else return BTreeSize(root->left)BTreeSize(root->right)1; } 方法二&#xff1a; 遍历计数&#xff1a;设置一个计数器&#xff0c;对二叉树正常访问&#…

Spring 是如何解决循环依赖问题的?

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 例如&#xff1a;项目场景&#xff1a;示例:通过蓝牙芯片(HC-05)与手机 APP 通信&#xff0c;每隔 5s 传输一批传感器数据(不是很大) 问题描述 我们都知道&#xff0c;如果在代码中&#xff0c;将两个…

高忆管理:券商板块探底回升,大市值券商企稳,中信建投涨超5%

近日活泼的券商板块8日盘中大幅回落&#xff0c;哈投股份一度跌停&#xff0c;后探底上升。大市值券商企稳&#xff0c;截至发稿&#xff0c;中金公司触及涨停&#xff0c;中信建投涨超5%。 首创证券一度大跌近9%&#xff0c;此前接连三日涨停&#xff0c;公司昨日晚间公告称&a…

【Vue】全家桶之vue-devtools

文章目录 概述安装使用componentsVuexEventsRoutingPerformanceSettings 来源 概述 Vue Devtools 是 Vue 官方发布的调试浏览器插件&#xff0c;可以安装在 Chrome 和 Firefox 等浏览器上&#xff0c;直接内嵌在开发者工具中&#xff0c;使用体验流畅。Vue Devtools 由 Vue.js…

9-数据结构-栈(C语言版)

数据结构-栈&#xff08;C语言版&#xff09; 目录 数据结构-栈&#xff08;C语言版&#xff09; 1.栈的基础知识 1.入栈&#xff0c;出栈的排列组合 情景二&#xff1a;Catalan函数&#xff08;计算不同出栈的总数&#xff09; 2.栈的基本操作 1.顺序存储 (1)顺序栈-定义…

在QT及VS运行包含opencv的cmakelists实例

本文分享如何利用QT和Visual Studio运行cmake组织管理的程序&#xff0c;也就是运行cmakelists.txt。 main和cmakelists内容 main和cmakelists文件路径如下&#xff1a; main.cpp #include<opencv2/opencv.hpp> #include<iostream> #include <string> usi…

ElementPlus 自定义主题(Vite4 + Vue3)

配置 ElementPlus 主题的时候遇到 SCSS 循环导入的报错&#xff0c;排查后发现是以为在 main.ts 和 vite.config.ts 中引入了两次自定义主题的样式文件&#xff0c;解决方法很简单&#xff0c;去掉 main.ts 中导入自定义主题的文件即可。这个问题发生在按需导入的时候&#xff…

vue实现大转盘抽奖

本案例为在小程序中实现的转盘抽奖&#xff0c;其他手机端项目思路类似。 注意&#xff1a; 转盘上的东西是由后台web项目里的配置页进行配置的&#xff0c;可以配置每个位置的奖品&#xff0c;中奖概率等。此文章只讲了抽奖转盘的实现&#xff0c;配置可根据真实需求进行开发…

web前端之CSS操作

文章目录 一、CSS操作1.1 html元素的style属性1.2 元素节点的style属性1.3 cssText属性 二、事件2.1 事件处理程序2.1.1 html事件2.1.2 DOM0事件&#xff08;适合单个事件&#xff09;2.1.3 DOM2事件&#xff08;适合多个事件&#xff09; 2.2 事件之鼠标事件2.3 事件之Event事…

网络编程的使用

文章目录 基础代码URL类进行传输编码解码 协议TCPUDPhttp PORT端口协议的实现TCPUDP 模拟服务器 基础代码 最后一个是&#xff1a;只要再timeout时间内连接上就是true URL类 导了一个common-iojar包&#xff0c;那个IOUtils就是那个里面的工具类 进行传输编码解码 协议 TC…

VSCode Remote-SSH (Windows)

1. VSCode 安装 VSCode 2. 安装扩展 Remote SSH Getting started Follow the step-by-step tutorial or if you have a simple SSH host setup, connect to it as follows: Press F1 and run the Remote-SSH: Open SSH Host… command.Enter your user and host/IP in the …

安防监控视频汇聚平台EasyCVR分发的FLV视频流在VLC中无法播放是什么原因?

众所周知&#xff0c;TSINGSEE青犀视频汇聚平台EasyCVR可支持多协议方式接入&#xff0c;包括主流标准协议国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。在视频流的处理与分发上&#xff0c;视频监控…

在SAP中使用苹果手机进行条码扫描

适用于iOS的Liquid UI支持使用内置摄像头或第三方设备&#xff08;如Linea Pro&#xff09;进行条形码扫描。它使您能够通过单击在任何 SAP 输入字段中填充数据。它支持&#xff1a;一维和二维条码扫描。此外&#xff0c;编辑扫描的数据或在扫描后对操作进行编程&#xff0c;以…

JWT的初步说明

JWT 概念 JWT 主要用于用户登录鉴权&#xff0c;JWT (全称&#xff1a;Json Web Token)是一个开放标准(RFC 7519)&#xff0c;它定义了一种紧凑的、自包含的方式&#xff0c;用于作为 JSON 对象在各方之间安全地传输信息。该信息可以被验证和信任&#xff0c;因为它是数字签名…

【深度学习注意力机制系列】—— SENet注意力机制(附pytorch实现)

深度学习中的注意力机制&#xff08;Attention Mechanism&#xff09;是一种模仿人类视觉和认知系统的方法&#xff0c;它允许神经网络在处理输入数据时集中注意力于相关的部分。通过引入注意力机制&#xff0c;神经网络能够自动地学习并选择性地关注输入中的重要信息&#xff…

巡课技巧,工作再忙也要学会!提高效率杠杠的

在当今不断演变的教育环境中&#xff0c;教学质量的提升和教师专业发展变得尤为重要。为了更好地监督和评估教师的教学表现&#xff0c;以及促进学生在课堂中的积极参与&#xff0c;在线巡课系统应运而生。 通过实时观察、远程巡课、数据分析等功能&#xff0c;该系统不仅为教育…

LVS负载均衡部署-NAT

文章目录 LVS-NAT模式配置原理实验环境DR添加网卡准备两台Real Server134&#xff1a;145&#xff1a;测试&#xff1a; 修改RS网关配置DR&#xff1a;开启路由转发下载软件配置查看配置 测试 LVS-NAT模式配置 原理 当客户端访问DR时即访问的外网接口然后由DR将流量在本地转发…

Do not access Object.prototype method ‘hasOwnProperty‘ from target object

调用 hasOwnProperty 报错&#xff1a;不要使用对象原型上的方法&#xff0c;因为原型的方法可能会被重写 if (this.formData.selectFields.hasOwnProperty(selectField)) {delete this.formData.selectFields[selectField];} else {this.formData.selectFields[selectField] …

HIVE学习

1.什么是HIVE 1.HIVE是什么? Hive是由Facebook开源&#xff0c;基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张表&#xff0c;并提供类SQL查询功能。 大白话: HIVE就是一个类似于Navicat的可视化客户端, 2.HIVE本质 Hive是一个Hadoop客户端&a…

Java、Android 之 TCP / IP

TCP、IP是一系列协议组成的网络分层模型 客户端向服务端发送请求可能会走N条链路&#xff0c;这个过程叫路由 TCP传输 一般在1--1024端口 必须连接以后才能传输数据 UDP协议通常只是发送数据 TCP连接 TCP需要建立连接才能通信&#xff0c;建立连接需要端口&#xff0c;Sock…