VS编译系统 实用调试技巧
目录
什么是bug?
调试是什么?有多重要?
debug和release的介绍
windows环境调试介绍、
一些调试实例
如何写出(易于调试)的代码
编程常见的错误
什么是bug?
其实bug在英文翻译中有表示臭虫的含义,因为第一次被发现的导致计算机程序错误的是飞蛾,也是第一个计算机程序错误。
调试是什么?有多重要?
写代码就是破案的过程,错误都是有迹可循的。迹象越多就越容易顺藤而上,这就是推理的途径。
发现错误-->调试-->解决错误
2.1调试的基本步骤:
发现程序错误的所在
以隔离、消除等方式对错误进行定位
确定错误产生的原因
提出错误的解决办法
对程序错误予以改正、重新测试
Debug和release的介绍(掌握)
Debug通常称为调试版本,它包含调试信息,并且不做任何优化,便于程序员调试。
Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便于用户很好的使用。
Debug和Release的区别就是Release的速度更快,所占的内存更少,但是Release不能调试,Debug可以进行调试。
windows环境调试介绍
3.1调试环境的准备
在环境中选择debug选项,才能使代码正常调试。
3.2调试快捷键
1.F5 - 开始调试
2.ctrl + F5 开始执行(不调试)
3.F9 设置断点/取消断点
4.F10 逐过程
5.F11 逐语句
使用Fn辅助功能键
F10和F11有什么区别呢?
他们在执行的过程F10是逐过程进行的,F11是逐语句进行的,所以在函数的调用时,F11可以更加细节的进入到函数的内部进行逐语句的调试。
F5是和F9配合使用的
F9是设置断点,F5是开始执行并跳到第一个断点
举例:
光标放到16行,按Fn+F9,我们就在16行加了一个断点,意思是F5开始调试直到断点处停止调试。
按F5开始调试
得到了我们的程序执行结果
在以上的基础上继续按F5开始调试结果会是什么样的呢?
在循环里面的断点,每次循环都会继续停到断点处。
抛开上面我们所说的,依然是下面的程序:
如果循环的次数很大,达到几百上千时,而我们的错误刚好在第400次循环时该怎么办呢?
在VS编译器中我们也可以设置断点。
如果我们不明白条件断点,我们也可以在代码中加上一条条件语句,之后将断点打在条件语句处,如果满足条件则断点被触发。
3.3调试时查看当前程序的信息
如果我们想在调试过程中观察i的值,点击调试->窗口->自动窗口
在我们按F10进行逐过程调试时,自动窗口会自动的显示我们在这个过程中,当前程序的信息。
如果我们想在调试过程中观察程序的局部变量的变化,点击调试->窗口->局部变量
如果我们想在调试过程中监视任何变量,点击调试->窗口->监视
监视不仅可以监视变量的值,也可以监视变量的地址,表达式的值
内存
调用堆栈
就是数据结构里面的栈。
反映数据的调用逻辑。
调试实例
求1!+2!+......+10!
int main()
{int n = 0;int sum = 0;scanf("%d", &n);int ret = 1;for (n = 1; n <= 10; n++){for (int i = 1; i <= n; i++){ret *= i;}sum += ret;}for (int i = 1; i <= n; i++){ret *= i;}printf("%d\n", sum);return 0;
}
经过计算,我们发现我们的代码是错误的,错误在于我们每一次循环没有及时修改ret的值为1。
但是如果我们不能一眼看出来错误在哪里,还是要依据调试来解决问题的。
1.在监视窗口中添加我们想要监视的变量
2.F11逐语句并且观察监视窗口中变量的值。
我们在调试的过程中发现ret在执行过程中,继续进行阶乘运算时,初始值不是1,这就是我们通过调试发现的问题所在,经过修改,代码如下:
int main()
{int n = 0;int sum = 0;//scanf("%d", &n);int ret = 1;int i = 0;for (n = 1; n <= 10; n++){ret = 1;for (int i = 1; i <= n; i++){ret *= i;}sum += ret;}for (int i = 1; i <= n; i++){ret *= i;}printf("%d\n", sum);return 0;
}
如何写出(易于调试)的代码
代码运行正常
bug很少
效率高
可读性高
可维护性高
注释清晰
文档齐全
常见coding技巧
使用assert
尽量使用const
养成良好的编码风格
添加必要的注释
避免编码的陷阱
示例:模拟实现strcpy函数
void my_strcpy(char* dest, char* scr)
{while (*scr != '\0'){*dest = *scr;dest++;scr++;}*dest = *scr;//'\0‘的拷贝
}
int main()
{char arr1[20] = "hello world";char arr2[40] = { 0 };my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}
但是在我们看来这样的代码并不是一个好的代码,我们可以继续将代码进行优化。
my_strcpy函数部分我们可以将它改为以下形式
void my_strcpy(char* dest, char* scr)
{while (*scr != '\0'){*dest++ = *scr++;//dest++;//scr++;}*dest = *scr;//'\0‘的拷贝
}
除了上述的代码形式外,我们还可以将代码改为以下形式:
void my_strcpy(char* dest, char* scr)
{while (*dest++ = *scr++){;}}
int main()
{char arr1[20] = "hello world";char arr2[40] = { 0 };my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}
但是我们在传递参数的时候不能够保证我们传递过来的指针是否为空指针,也不能保证指针的有效性,所以在这个时候我们就要使用assert断言,来保证指针的有效性。
为什么使用assert断言?
如果在传参的这个过程中,我们真的传递了一个空指针,或者说是一个无效的指针,那么使用断言就会提示我们这样的问题所在,但是如果你没有使用断言来判断指针的有效性,整个程序运行起来的最终结果就会崩掉,并且同时我们也不会知道它为什么会运行失败。
#include <assert.h>
void my_strcpy(char* dest, char* scr)
{//assert(dest != NULL);//assert(scr != NULL);assert(dest && scr);while (*dest++ = *scr++){;}}
int main()
{char arr1[20] = "hello world";char arr2[40] = { 0 };my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}
当然断言不仅仅是应用于指针的判断,断言是依据assert后面表达式真假而言的。对于我们程序员来讲是一个很好的编程习惯。
other:
我们在C语言的库中发现strcpy函数和我们自己写的my_strcpy函数有所出入。详细请看下图:
使用const修饰和不使用const又有什么区别呢?
const修饰指针的作用:
const放在*的左面,const int* p或者int const* p,const放在*的左面限制的是*p而不是p。
*p不能改,是p指向的内容;但是p可以改,p可以指向其他变量
int main()
{const int m = 0;int n = 0;//m = 20;errconst int* p = &m;//*p = 20;错误p = &n;//okreturn 0;
}
const放在*的右面,int* const p ,如果const放在*右边,限制的是p而不是*p,*p可以改,p不可以改。
int main()
{int m = 0;int n = 0;int* const p = &m;*p = 20;//okp = &n;//noreturn 0;
}
在我们strcpy中是如何使用的呢?
如果我们将源头和目的地写反,就出现了一个bug,这个时候使用const修饰char* scr就可以避免这个错误。提高了代码的健壮性。
#include <assert.h>
void my_strcpy(char* dest, const char* scr)//意思是*scr不能被改变
{//assert(dest != NULL);//assert(scr != NULL);assert(dest && scr);while (*dest++ = *scr++){;}}
int main()
{char arr1[20] = "hello world";char arr2[40] = { 0 };my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}
#include <assert.h>
char* my_strcpy(char* dest, const char* scr)//意思是*scr不能被改变
{//strcpy函数返回的是目标空间的起始地址assert(dest && scr);char* ret = dest;//记住起始空间的地址while (*dest++ = *scr++){; }return ret;
}
int main()
{char arr1[20] = "hello world";char arr2[40] = { 0 };//链式访问printf("%s\n", my_strcpy(arr2, arr1));return 0;
}
编程常见的错误
6.1编译型错误
例如:缺少分号等语法错误,可以直接查看错误信息,解决问题。
6.2链接型错误
例如:拼写错误,或者标识符不存在提示有无法解析的外部命令。
主要在代码中找到错误信息的标识符,然后定位问题所在。
ctrl+f--搜索
6.3运行时错误
借助调试,逐步定位问题。
感谢阅读,欢迎大家批评指正!
相关文章:
VS编译系统 实用调试技巧
目录什么是bug?调试是什么?有多重要?debug和release的介绍windows环境调试介绍、一些调试实例如何写出(易于调试)的代码编程常见的错误什么是bug?其实bug在英文翻译中有表示臭虫的含义,因为第一次被发现的导致计算机…...
【华为OD机试模拟题】用 C++ 实现 - GPU 调度(2023.Q1)
最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明GPU 调度题目输入输出示例一输入输出说明示例二输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。...
腾讯前端必会react面试题合集
React-Router的路由有几种模式? React-Router 支持使用 hash(对应 HashRouter)和 browser(对应 BrowserRouter) 两种路由规则, react-router-dom 提供了 BrowserRouter 和 HashRouter 两个组件来实现应用的…...
Linux搭建SVN服务器,并内网穿透实现公网远程访问
文章目录1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6.2 配置…...
C++STL之list的模拟实现
目录 一.list准备 二. iterator迭代器 1._list_iterator 2.begin()、end() 3.const_begin()、const_end() 4.!&& 5. && -- 6.operator* 7.operator-> 三.Modify(修改) 1.insert() 2.erase() 3.push_back() && push_front() 4.pop_bac…...
为什么硬件性能监控很重要
当今的混合网络环境平衡了分布式网络和现代技术的实施。但它们并不缺少一个核心组件:服务器。保持网络正常运行时间归结为监控和管理导致网络停机的因素。极有可能导致性能异常的此类因素之一是硬件。使用硬件监控器监控网络硬件已成为一项关键需求。 硬件监视器是…...
HTTP缓存
HTTP缓存HTTP缓存引发的一个问题HTTP缓存的作用HTTP缓存的分类强制缓存协商缓存(解决强缓存下资源不更新问题)缓存策略HTTP缓存引发的一个问题 有一次在开发移动端H5项目,UI提了几个UI问题,经过样式调试,android上没有…...
SPI设备树处理过程
SPI设备树处理过程 文章目录SPI设备树处理过程参考资料:一、 spi_device结构体二、 SPI设备树格式2.1 SPI Master2.2 SPI Device2.3 设备树示例三、设备树实例3.1 使用GPIO模拟的SPI控制器3.2 IMX6ULL SPI控制器四、 设备树处理过程致谢参考资料: 内核头…...
数据有哪些重要的作用?
我们正处在科技高速发展的时代,如今互联网已经与我们的生活息息相关,我们每天在互联网产生大量的数据,这些数据散落在网络中看似没有怎么作用,但是这些数据经过系统的处理整合起来确实非常有价值的。 一、 发展大数据技术可以提高…...
spring面试题总结
1、spring是什么? spring是一个轻量级IOC和AOP容器框架,是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用的开发,开发者只需要关注业务需求即可: core container 容器组件 spring context,…...
使用MUI与H5+构建移动端app
前言 通过mui构建APP 效果图: <!DOCTYPE html> <html> <head><meta charset...
第17篇:Java变量总结
目录 1.变量的概念 1.1 变量来源 1.2 计算机中的变量 1.3 变量如何在内存中存储 2.Java变量...
使用51单片机的GPIO输出占空比可调节的PWM波
一、前言 在一些单片机或微控制器中,通用GPIO可以被配置为产生PWM信号。PWM即脉冲宽度调制,是一种用于模拟输出的技术。它可以通过改变输出信号的脉冲宽度来控制电路中的电平,从而实现对电路的控制。 二、什么是PWM波? PWM波&a…...
从产品经理的角度如何提升项目的交付质量?
提高交付质量 ,对于每个IT公司都是永恒的话题。 交付质量其实包含2重意义, 一是交付的高质量(客户角度),即客户的满意度;二是高质量的交付(交付团队的角度),这里是指如何…...
JavaScript BOM【快速掌握知识点】
目录 Window对象的常用属性 语法: Window对象的常用方法 语法: open()和close()方法 History对象 常用属性和方法 示例 Location对象 常用属性 常用方法 Document对象的常用方法 定时函数 超时调用:setTimeout() 间歇调用&…...
【算法】哈希表
作者:指针不指南吗 专栏:算法篇 🐾或许会很慢,但是不可以停下来🐾 文章目录1.定义2.优点3.数字哈希3.1拉链法3.2开放寻址法3.3 例题4.字符串哈希1.定义 哈希表(Hash table),是根据键…...
彻底搞懂React-hook链表构建原理
写在前面的小结 每一个 hook 函数都有对应的 hook 对象保存状态信息useContext是唯一一个不需要添加到 hook 链表的 hook 函数只有 useEffect、useLayoutEffect 以及 useImperativeHandle 这三个 hook 具有副作用,在 render 阶段需要给函数组件 fiber 添加对应的副…...
【数据挖掘实战】——应用系统负载分析与容量预测(ARIMA模型)
项目地址:Datamining_project: 数据挖掘实战项目代码 目录 一、背景和挖掘目标 1、问题背景 2、传统方法的不足 2、原始数据 3、挖掘目标 二、分析方法与过程 1、初步分析 2、总体流程 第一步:数据抽取 第二步:探索分析 第三步&a…...
【华为OD机试模拟题】用 C++ 实现 - 九宫格按键输入(2023.Q1)
最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明九宫格按键输入题目输入输出示例一输入输出说明示例二输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高…...
Linux: config: CONFIG_SYN_COOKIES
文章目录 CONFIG_SYN_COOKIESLinux kernel里的超时设置Huawei SBC详细工作机制CONFIG_SYN_COOKIES config SYN_COOKIES,布尔值;是否支持IP:TCP syncookie功能。 详解:一般来说TCP/IP网络不能够阻挡SYN flooding工具。这个工具很容易被利用,而且会导致DOS工具,妨碍其他整…...
【笔记】C# 数据类型转换
文章目录前言类型转换的概念1,隐式转换2,显式转换3,程序类转换结语前言 🌻 大家好啊,我是writer桑,本章是关于 C# 数据类型转换的一个总结,其中包含隐式、显示转换和程序类转换,方便…...
JavaWeb JavaBean,MVC三层架构
9、JavaBean 实体类 JavaBean有特定的写法: 必须要有一个无参构造属性必须私有化必须有对应的get/set方法; 一般用来和数据库的字段做映射 ORM; ORM :对象关系映射 表—>类字段–>属性行记录---->对象 people表 …...
JavaEE简单实例——MyBatis一对多关联映射的嵌套结果集查询
简单介绍: 在之前的章节,我们简单介绍了MyBatis中的一对一的关联查询,使用了嵌套查询和嵌套结果集两种方式进行讲解,但是在实际的使用中,我们常用的是嵌套结果集的查询方式,所以在一对多的查询中ÿ…...
大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——OutputFormat数据输出
3.6.1OutputFormat接口实现类 OutputFormat是MapReduce输出的基类,所有实现MapReduce输出都实现了OutputFormat接口。下面我们介绍几种常见的OutputFormat实现类。 1、文本输出TextOutputFormat 默认的输出格式是TextOutputFormat,它把每条记录写为文…...
Linux搜索、编辑
目录 1.搜索 1.1.基础用法 1.2.高级用法 2.编辑 2.1.vim简洁 2.2.vim快捷键 1.搜索 1.1.基础用法 find命令用于搜索,格式如下: find 指定目录 -匹配方式 所要匹配的关键字 所要匹配的关键字支持通配符,?代表一个字符*代表任意个字符。 如果想设…...
Git Commit提交规范总结
文章目录前言git commit 提交规范提交消息头(commit message header)提交消息具体内容(commit message body)提交消息尾述(commit message footer)Revert表情(Emojis)标识idea插件其他操作Commitizen生成 Change logGit获取提交消息格式化输出相关参考前言 我们都知道…...
【ESP 保姆级教程】疯狂毕设篇 —— 案例:基于ESP8266和EMQX的教室灯光控制系统
忘记过去,超越自己 ❤️ 博客主页 单片机菜鸟哥,一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-02-26 ❤️❤️ 本篇更新记录 2022-02-26 ❤️🎉 欢迎关注 🔎点赞 👍收藏 ⭐️留言📝🙏 此博客均由博主单独编写,不存在任何商业团队运营,如发现错误,请…...
SpringBoot (一) 项目构建、配置读取、静态资源定义
哈喽,大家好,我是有勇气的牛排(全网同名)🐮 有问题的小伙伴欢迎在文末评论,点赞、收藏是对我最大的支持!!!。 前言 SpringBoot是基于Spring开发的开源项目,…...
<JVM上篇:内存与垃圾回收篇>12 - 垃圾回收相关概念
笔记来源:尚硅谷 JVM 全套教程,百万播放,全网巅峰(宋红康详解 java 虚拟机) 文章目录12.1. System.gc()的理解12.2. 内存溢出与内存泄露内存溢出(OOM)内存泄漏(Memory Leakÿ…...
new操作符做了什么?
new是什么? new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 function Person (name,age) {this.name namethis.age age } Person.prototype.sayName function () {console.log(this.name) } let man new Person(xl,20) consol…...
网赌网站做流量渗透/微信小程序开发多少钱
AutoJs一键解密是一款电脑上的AutoJs脚本文件解密工具,有了它,你可以对任何一个AutoJs脚本进行一键解密操作。具体使用情况请有需要的朋友前来西西下载!软件初衷最近论坛用AutoJS编写的脚本程序越来越多,每次审核都要拖进手机才能…...
做算命网站赚钱吗/商品热搜词排行榜
Loadrunner在场景中添加多个负载机报错:Action.c(38): Error -26488: Could not obtain information about submitted解决方法参考文章: (1)Loadrunner在场景中添加多个负载机报错:Action.c(38): Error -26488: Could…...
大型门户网站源码/seo网站优化方
对于二进制表示的float类型的2.5,其在内存中的表示为01000000 00100000 00000000 00000000,如果我们想打印出它在内存中是如何表示的,那么我们可以用1进行移位,与每个比特进行与运算,还是看看代码吧: 对…...
企业管理系统网站开发标书/青岛网站排名推广
前言: Servlet的作用: Servlet 是接口,是 JavaEE 规范之一。接口起到了规范的作用。Servlet 是 JavaWeb 三大组件之一。三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。Servlet 是运行在服务器上的一个 java 小程序,它可以接…...
做厂家批发的网站/学电脑办公软件培训班
一、总体说明 XML和JSON 是最为常用的数据交换格式本例子演示如何将java对象,转成XML输出。二、流程1.在上文的例子中,创建一个包“com.waylau.rest.bean”2.在该包下创建一个JAVA类”User”package com.waylau.rest.bean; import javax.xml.bind.annota…...
建网站被封了/百度手机助手app下载官网
第二章 项目初始化和第一个小例子.md初始化项目项目目录介绍自定义爬虫类自定义第一个爬虫录入代码代码解释:运行爬虫运行结果代码逐条分析简易版本经过了上一章的学习,我们已经在开发环境上安装好了scrapy的包,接下来我们就将初始化一个项目…...