实用调试技巧(1)
- 什么是bug?
- 调试是什么?有多重要?
- debug和release的介绍。
- windows环境调试介绍。
- 一些调试的实例。
- 如何写出好(易于调试)的代码。
- 编程常见的错误。
什么是Bug
我们在写代码的时候遇到的一些问题而导致程序出问题的就是Bug,世界上的第一个Bug是一支飞蛾,这就是Bug的由来,在早期的时候,机器突然坏了,工作人员进行检查,最后发现是一只飞蛾导致机器故障,所以也有了现在的Bug之称。
当天的工作人员将他贴在了笔记本上,这就是时间上的第一个Bug。
调试是什么
我们在初学的时候会遇到各种各样的问题,这个时候我们就需要进行调试,这样才能解决Bug,所以调试非常重要,一个出色的程序员必须会调试
所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有愧,就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺藤而上,这就是推理的途径。
顺着这条途径顺流而下就是犯罪,逆流而上,就是真相。
但是我们在初学的时候总是盲目的调试,可能只是简单摁下键盘上的F10,调试一直到我们代码结束的时候,只是走了一遍流程,却不知道问题在哪里,这就是我们初学者经常出现的问题。
所以我们要拒绝迷信调试,要真正的找到问题所在,解决这个臭虫
2.1 调试是什么?
调试(英语:Debugging / Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。
2.2 调试的基本步骤
- 发现程序错误的存在
- 以隔离、消除等方式对错误进行定位
- 确定错误产生的原因
- 提出纠正错误的解决办法
- 对程序错误予以改正,重新测试
而我们写程序的时候出现Bug生活中一般有三种人,一是程序员自己,二是测试员,三是用户。
测试员就是相当于你写的代码经过relase之后到测试员那里,它进行测试。
3 Debug和Release的介绍
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
就是相当于我们平常在编译器上写的代码
Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
这个就是我们的代码经过优化后呈现给用户的
那我们用代码给大家演示一下他们有什么不一样的地方
#include<stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6 };int i = 0;for (i = 0; i < 10; i++){arr[i] = -1;}for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
上面就是我们在Debug和release下生成的可执行文件
很明显Release下的内存明显小了很多,说名它进行过优化,我们这是在X86平台下,就是32位机器下,当然我们改成X64也是一样的道理
3. Windows环境调试介绍
那我们在了解环境之前先要来了解一些东西,比如就是快捷键,何为快捷键,就是让你变得快捷起来。
在我们的调试里头就有这些快捷键,来介绍几个常用的
CTRL + F5
这个键就是我们每次运行要得到我们的结果的时候用的,它的意思就是开始执行不调试,直接运行程序。
F11
这个就是一条一条语句往下执行,我们在调试过程中这是必然不可缺少的,它也可以进到我们的函数当中去。
F10
逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句
F10和F11其实差不多,就是后者更细致一点,作用都是差不多的。
F9
创建断点和取消断点断点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
F5
启动调试,经常用来直接跳到下一个断点处.
下面举例子给大家看看断点有多方便。
#include<stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6 };int i = 0;for (i = 0; i < 10; i++){arr[i] = -1;}for (i = 0; i < 10; i++){printf("%d ", arr[i]);}printf("\n");for (i = 0; i < 10; i++){printf("hehe\n");}return 0;
}
我们在上面设置了一个断点,并且条件是i==6,那让我们按下F5看看吧。
上面我只按了一个F5就到了,可是如果我按F10,要经过一个半的for循环,有时候按的快的时候,一下子按过头了又要重新按(小编一开始就是这么蠢,大家学聪明点),可见断点和F5连用是这么方便。
同时屏幕上也打印了6个-1
还有其他相当多的快捷键大家也可以去网上找找,增加对VS的理解
会快捷键之后我们还需要学习一些其他的,往下看
3.3 调试的时候查看程序当前信息
在窗口里有各式各样的好东西,让我们来看看吧
当然我们这些窗口必须是要开始调试起来的时候才能看到,我一开始学的时候,不知道这个,废了好大劲才找到我原来都没有开始调试。
监视窗口
任意选一个都可以,在这里我们就可以输入我们想要监视的,比如数组名,还有数组的元素,一些变量,我们都可以看到它时刻的值,当然大家也可以看到自动窗口和局部变量,这些也都是监视的,只不过它是自己生成的,虽然很方便但是它有时候会自己变值,总的来说还是不便于观察,我们在学得时候,小编建议大家还是自己尝试,这样才能提升自己的调试技巧。
内存窗口
这个也很重要,我们在栈上创建变量的时候,都是占用空间的,而我们会用相应的编号找到他们的位置,这也是让我们更好的观察他们,让我们更容易调试,找到Bug。
3.3 查看调用堆栈
调用堆栈主要是反映逻辑关系,比如我们过多的调用函数的时候不明白它的逻辑的时候可以使用
举个例子
#include<stdio.h>
void test1()
{printf("hehe\n");
}
void test()
{test1();
}
int main()
{test();return 0;
}
我们返回的时候是下面这样
啥意思呢,就是我们之前讲过函数栈帧一样,栈是一步一步在顶上开辟,然后一步一步返回的。
3.4 查看汇编信息
在函数栈帧讲过,建议大家去看一下
3.5 查看寄存器信息
之前讲过esp和ebp还有edi这些,他们的作用都是一样,存储数据,其中ebp和esp有维护函数栈帧的作用。
接下来给两个例子给大家调试一下看,不过都是最基础的调试.
实例
实现代码:求 1!+2!+3! …+ n! ;不考虑溢出。
int main()
{int i = 0;int sum = 0;//保存最终结果int n = 0;int ret = 1;//保存n的阶乘scanf("%d", &n);for(i=1; i<=n; i++){int j = 0;for(j=1; j<=i; j++){ret *= j;}sum += ret;}printf("%d\n", sum);return 0;
}
我们的代码主要是为了计算阶乘的大小,前几个阶乘相加计算出结果,但是我们上面的代码其实是有问题的,我们一步一步调试来看看,首先我们要写出我们每次心里想的结果去对比编译器中监视进行对比,找出问题。
调试之前可以像我一样把要观察的写出来
j循环的for语句执行一次,因为i=1,算出1的阶乘,答案是对的。
我们看2的阶乘
其实我们在这里就能看出结果,原因是我们是在原来的基础性上阶乘,但是运气好,答案是对的,当我们继续往下走,就会看出端倪
一看和我们预想的有问题,这时候就要警惕,如果我们第一次没看出来,但是结果不一样,这时候就要小心了,不过很显然,为什么造成这个原因,我们在调试过程一看就才可以看出来了,ret一直是在原来基础上改变,所以我们给他进入循环的时候变成1就可以了。
改正
#include<stdio.h>int main()
{int i = 0;int sum = 0;//保存最终结果int n = 0;int ret = 1;//保存n的阶乘scanf("%d", &n);for (i = 1; i <= n; i++){int j = 0;ret = 1;for (j = 1; j <= i; j++){ret *= j;}sum += ret;}printf("%d\n", sum);return 0;
}
实例two
#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;
}
想要解释这道题必须调试才能知道
给个前提,必须在VS这个编译器下,而且是X86,Debug下,别的一些编译器也行,但还是有点初入,这里我们不进行调试是做不出来,下面调试。
当我们的i变成9的时候,刚刚把原始数组都赋值为0
很神奇,我们数组下标到9就应该结束,但是现在竟然把arr[10]的内容赋值为0,我们语句越界访问了
11也是,i还在变大
arr[12]怎么放的是i的值,好奇怪,我们继续往下。
i突然变成0了,arr[12]的内容也是0,说明赋值成功,但是i又变了。我们就要去怀疑他们是不是公用一个空间
结果一看还真是,那就说明arr[12]和i用的是一个地址,后来i又变成0了,所以才会死循环,讲到这里大家肯定明白了把
图
说面我们arr数组开辟的时候和i中间差两个整型,我们数组的下标是由低地址到高地址的
今天我们先讲一部分调试技巧,内容太多了,小编写不动了,谢谢大家!!!
相关文章:

实用调试技巧(1)
什么是bug?调试是什么?有多重要?debug和release的介绍。windows环境调试介绍。一些调试的实例。如何写出好(易于调试)的代码。编程常见的错误。 什么是Bug 我们在写代码的时候遇到的一些问题而导致程序出问题的就是Bu…...

uniapp:H5定位当前省市区街道信息
高德地图api,H5定位省市区街道信息。 由于uniapp的uni.getLocation在H5不能获取到省市区街道信息,所以这里使用高德的逆地理编码接口地址接口,通过传key和当前经纬度,获取到省市区街道数据。 这里需要注意的是:**高德…...

自然语言处理从入门到应用——LangChain:提示(Prompts)-[提示模板:部分填充的提示模板和提示合成]
分类目录:《自然语言处理从入门到应用》总目录 部分填充的提示模板 提示模板是一个具有.format方法的类,它接受一个键值映射并返回一个字符串(一个提示),以传递给语言模型。与其他方法一样,将提示模板进行…...

论文笔记--GloVe: Global Vectors for Word Representation
论文笔记--GloVe: Global Vectors for Word Representation 1. 文章简介2. 文章概括3 文章重点技术3.1 两种常用的单词向量训练方法3.2 GloVe3.3 模型的复杂度 4. 文章亮点5. 原文传送门6. References 1. 文章简介 标题:GloVe: Global Vectors for Word Representa…...

day57|● 647. 回文子串 ● 516.最长回文子序列
647. 回文子串 https://leetcode.cn/problems/palindromic-substrings/solution/by-lfool-2mvg/ Given a string s, return the number of palindromic substrings in it. A string is a palindrome when it reads the same backward as forward. A substring is a contiguous…...

docker compose.yml学习
docker compose 安装docker-compose sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composechmod x /usr/local/bin/docker-composeln -s /usr/local/bin/docker-…...

【业务功能篇55】Springboot+easyPOI 导入导出
Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。 Apache POI 代码实现复杂,学习成本较高。 Easypoi 功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出…...

对顶堆算法
对顶堆可以动态维护一个序列上的第k大的数,由一个大根堆和一个小根堆组成, 小根堆维护前k大的数(包含第k个)大根堆维护比第k个数小的数 [CSP-J2020] 直播获奖 题目描述 NOI2130 即将举行。为了增加观赏性,CCF 决定逐一评出每个选手的成绩&a…...

node.js的优点
提示:node.js的优点 文章目录 一、什么是node.js二、node.js的特性 一、什么是node.js 提示:什么是node.js? Node.js发布于2009年5月,由Ryan Dahl开发,是一个基于ChromeV8引擎的JavaScript运行环境,使用了一个事件驱…...

golang编译跨平台
golang可以在windows上编译出linux、MacOS等系统上的程序。 go编译器windows下可变翼linux程序,例如,GOARCHamd64 和 GOOSlinux 可以用于编译 64 位的 Linux 平台上的可执行文件。: set GOARCHamd64 set GOOSlinux go build main.go通过设置…...

关于Spring的bean的相关注解以及其简单使用方法
一、前置工作 第一步:创建一个maven项目 第二步:在resource中创建一个名字叫做spring-config.xml的文件,并把以下代码复制粘贴 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.sprin…...

【计算机视觉】BLIP:源代码示例demo(含源代码)
文章目录 一、Image Captioning二、VQA三、Feature Extraction四、Image-Text Matching 一、Image Captioning 首先配置代码: import sys if google.colab in sys.modules:print(Running in Colab.)!pip3 install transformers4.15.0 timm0.4.12 fairscale0.4.4!g…...

TWILIGHT靶场详解
TWILIGHT靶场详解 下载地址:https://download.vulnhub.com/sunset/twilight.7z 这是一个比较简单的靶场,拿到IP后我们扫描发现开启了超级多的端口 其实这些端口一点用都没有,在我的方法中 但是也有不同的方法可以拿权限,就需要…...

【案例】--GPT衍生应用案例
目录 一、前言二、GPT实现智能问答架构2.1、基本的GPT实现智能问答架构2.2、可应用的GPT实现智能问答架构1、语义转换2、相似度关键字矩阵3、ES中搜索相似度关键字矩阵三、后续一、前言 GPT,全称Generative Pre-trained Transformer ,中文名可译作生成式预训练Transformer。…...

Sip网络音频对讲广播模块, sip网络寻呼话筒音频模块
Sip网络音频对讲广播模块, sip网络寻呼话筒音频模块 一、模块介绍 SV-2101VP和 SV-2103VP网络音频对讲广播模块 是一款通用的独立SIP音频功能模块,可以轻松地嵌入到OEM产品中。该模块对来自网络的SIP协议及RTP音频流进行编解码。 该模块支持多种网络协议…...

leetcode1219. 黄金矿工(java)
黄金矿工 leetcode1219. 黄金矿工题目描述回溯算法代码 回溯算法 leetcode1219. 黄金矿工 难度: 中等 eetcode 1219 黄金矿工 题目描述 你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元…...

Svelte框架入门
关键词 前端框架、编译器、响应式、模板 介绍 Svelte /svelt/ adj. 苗条的;线条清晰的;和蔼的 Svelte是一个前端组件框架,就像它的英文名字一样,Svelte的目标是打造一个更高性能的响应性前端框架。 Svelte类似于React和Vue框架&am…...

在linux中进行arm交叉编译体验tiny6410裸机程序开发流程
在某鱼上找了一个友善之臂的Tiny6410开发板用来体验一下嵌入式开发。这次先体验一下裸机程序的开发流程,由于这个开发板比较老旧了,官方文档有很多过期的内容,所以记录一下整个过程。 1. 交叉编译器安装 按照光盘A中的文档《04- Tiny6410 L…...

SpringBoot实战(二十三)集成 SkyWalking
目录 一、简介二、拉取镜像并部署1.拉取镜像2.运行skywalking-oap容器3.运行skywalking-ui容器4.访问页面 三、下载解压 agent1.下载2.解压 四、创建 skywalking-demo 项目1.Maven依赖2.application.yml3.DemoController.java 五、构建启动脚本1.startup.bat2.执行启动脚本3.发…...

深度学习实践——卷积神经网络实践:裂缝识别
深度学习实践——卷积神经网络实践:裂缝识别 系列实验 深度学习实践——卷积神经网络实践:裂缝识别 深度学习实践——循环神经网络实践 深度学习实践——模型部署优化实践 深度学习实践——模型推理优化练习 深度学习实践——卷积神经网络实践ÿ…...

linux | vscode | makefile | c++编译和调试
简单介绍环境: vscode 、centos、 gcc、g、makefile 简单来说就是,写好项目然后再自己写makefile脚本实现编译。所以看这篇博客的用户需要了解gcc编译的一些常用命令以及makefile语法。在网上看了很多教程,以及官网也看了很多次,最…...

Spring | Bean 作用域和生命周期
一、通过一个案例来看 Bean 作用域的问题 Spring 是用来读取和存储 Bean,因此在 Spring 中 Bean 是最核心的操作资源,所以接下来我们深入学习⼀下 Bean 对象 假设现在有⼀个公共的 Bean,提供给 A 用户和 B 用户使用,然而在使用的…...

培训(c++题解)
题目描述 某培训机构的学员有如下信息: 姓名(字符串)年龄(周岁,整数)去年 NOIP 成绩(整数,且保证是 5 的倍数) 经过为期一年的培训,所有同学的成绩都有所提…...

ansible-playbook编写 lnmp 剧本
ansible-playbook编写 lnmp 剧本 vim /opt/lnmp/lnmp.yaml执行剧本 ansible-playbook lnmp.yaml...

需求太多处理不过来?MoSCoW模型帮你
一、MoSCoW模型是什么 MoSCoW模型 是在项目管理、软件开发中使用的一种排序优先级的方法,以便开发人员、产品经理、客户对每个需求交付的重要性达成共识。 MoSCoW是一个首字母缩略词,代表: M(Must have):…...

Vue 3:玩一下web前端技术(六)
前言 本章内容为VUE请求后端技术与相关技术讨论。 上一篇文章地址: Vue 3:玩一下web前端技术(五)_Lion King的博客-CSDN博客 下一篇文章地址: Vue 3:玩一下web前端技术(七)_Lio…...

【点云处理教程】00计算机视觉的Open3D简介
一、说明 Open3D 是一个开源库,使开发人员能够处理 3D 数据。它提供了一组用于 3D 数据处理、可视化和机器学习任务的工具。该库支持各种数据格式,例如 .ply、.obj、.stl 和 .xyz,并允许用户创建自定义数据结构并在程序中访问它们。 Open3D 广…...

Windows10系统还原操作
哈喽,大家好,我是雷工! 复制了下虚拟机的Win10系统,但其中有一些软件,想实现类似手机的格式化出厂操作,下面记录Windows10系统的还原操作。 一、系统环境: 虚拟机内的Windows10,64…...

Django学习笔记-模板(Template)基础
使用模块可以很方便的执行一些数据操作,然后根据传入的数据直接在模板html文件中进行处理。 1.Django中的模板配置 Django的模板引擎在sttings.py文件中: TEMPLATES [{# 模板引擎,默认为django模板BACKEND: django.template.backends.dja…...

使用 NVM(Node Version Manager)管理 Node.js 版本
使用 NVM(Node Version Manager)管理 Node.js 版本 步骤一:安装 NVM NVM 是一个用于安装和管理不同版本的 Node.js 的工具。首先,你需要确保你的系统上已经安装了 NVM。可以通过以下命令检查 NVM 是否已经安装: nvm …...