C语言第二十课:实用调试技巧

news2024/12/27 10:45:59

目录

前言:

一、Bug:

二、调试:

        1.调试是什么:

        2.调试的基本步骤:

        3. Debug 与 Release :

三、在Windows环境下进行调试:

        1.调试环境的准备:

        2.调试的快捷键:

        3.调试查看程序当前信息:

        ①.查看临时变量的值:

        ②.查看内存信息:

        ③.查看调用堆栈:

        ④.查看汇编信息:

        ⑤.查看寄存器信息:

四、如何写出好的代码:

五、编程常见错误:

        1.编译型错误:

        2.链接型错误:

        3.运行时错误:

六、总结:


892bef7cd61f47feb732e807c0731636.jpeg

前言:

        在前面的十九篇文章中,我们较为系统的学习了C语言的各种语法结构,相信此时的各位小伙伴们已经有能力写出一些简单的C语言程序了。而今天我将要带领各位小伙伴们学习初阶C语言的最后一课——调试。并且今天的课程较为轻松,主要是为大家介绍一些实用的调试小技巧,能希望能对大家的代码查错和调有所帮助。

一、Bug:

        作为一名程序员,bug这个词应该是耳熟能详。相信你们在平时在身边小伙伴们的口中也一定常常听到这个词汇,那么bug到底是什么呢?它又是如何产生的呢?

        英文的 Bug,即臭虫,翻译成中文为程序缺陷,是指在软件运行中因为程序本身有错误而造成的功能不正常、死机、数据丢失、非正常中断等现象

        而程序错误之所以被称为“臭虫”,还要从一位老奶奶说起。这个人,就是与阿兰·图灵、史蒂夫·乔布斯、比尔·盖茨等一同入选“IT界十大最有远见的人才”的唯一一位女性——格蕾丝·赫柏

0daada3cb8d24d7d8e1e1412c86d4c56.webp

        1906年,赫柏出生在美国纽约。从上学起,赫柏在数学、物理方面都异常出色,一路顺顺利利直到16岁参加高考,却因为偏科太严重,拉丁文考试不及格,没能考上大学。复读一年后,赫柏考上韦莎学院。这所大学在2012年《福布斯》公布的美国最好大学中排名第20位,新闻报道更是将它评价为最值得选择的大学。毕业时,赫柏不仅同时获得数学、物理学位,还获得美国优等生的荣誉,留校担任教师的她被聘为学院副教授。赫柏的曾祖父是一名海军将军。1939年二战爆发时,满怀爱国热情的赫柏也坚决要求加入海军,毕业的赫柏因为出色的数学背景,被分配到美国船舶局位于哈佛大学的战时科研中心。彼时,军方正在开展世界第一台大型数字计算机的研究项目——马克一号。赫柏被任命为著名计算机专家霍德艾肯博士的助手,成为这个项目的第三名程序员。一天,计算机发生故障,赫柏经过排查,在计算机的继电器触电里,找到了一只被夹扁的小飞蛾,这只小虫子卡住了机器的运行,赫柏顺手将飞蛾夹在工作笔记里,并诙谐的把程序故障称为“bug”。这就是我们今天最爱说的“bug”的由来。它的意思,和原身一致,真就是“一只臭虫”。

ab9bb9c390c1464097cac683d1c0b03e.webp

        这一称呼后来演变成表达缺陷漏洞的计算机专业术语,人们习惯地把排除程序故障叫做“debug”(除虫)。

二、调试:

        一名优秀的程序员也是一名出色的侦探每一次调试都是一次破案的过程。所有要发生的事情都一定有迹可循,问心无愧就不存在痕迹,自然无需遮遮掩掩,倘若问心有愧,则必然遮掩一番,一旦遮掩就一定会留下痕迹,而留下的痕迹越多,就越容易顺藤而上,这就是推理的途径。顺着这条途径顺流而下就是犯罪,逆流而上,则是真相。

        那么我们是怎么写代码的呢?我相信很多小伙伴们在写代码时都是这样的

        可是编写代码一股脑闷着写就可以了吗?答案自然是不行。这样不管不顾的去编写代码,最后一般会产生两个经典问题这程序为什么跑不起来?这程序又是怎么跑起来的呢?

acd8ed41f0d74b738b0df0d5b5e9a6a4.jpeg

        当遇到这样的问题的时候,就需要我们对程序进行调试,来验证和查看我们程序的每一个运行细节

        1.调试是什么:

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

        调试是一个多步骤的过程,包括识别问题隔离问题源,然后纠正问题或确定解决问题的方法。在软件开发中,调试涉及定位纠正计算机程序中的代码错误。调试过程在编写代码后立即开始,并随着代码与其他编程单元组合形成软件产品而在连续阶段继续进行。通过使用单元测试代码审查结对编程等策略,可以使调试过程更容易。

        2.调试的基本步骤:

        · 发现程序错误的存在

        · 以隔离、消除等方式对存物进行定位

        · 确定错误产生的成因

        · 提出纠正错误的解决办法

        · 对程序错误予以改正重新测试

        3. Debug 与 Release :

        我们的 VS 2022 内置有两种编译版本,分别是 Debug 版本Release 版本,两种版本村踩着一定的差异。

        Debug 版本通常称为调试版本,它包含调试信息,并且不做任何优化便于程序员调试程序。

        Release 版本通常则被称为发布版本,它往往会对我们的代码进行各种优化使得程序在代码大小和运行速度上都是最优的以便用户很好的使用

        这两种版本在很多地方都存在着差异,我们以下面这段代码为例:

#define _CRT_SECURE_NO_WARNINGS 1

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

        为了进行演示,我们故意写出了一个bug程序,即在进行数组元素访问时,使其越界访问

        首先我们来看本地文件的差别(上为 Debug 版本,下为 Release 版本):

0b0af7e140ad44919a6a178d88ff8e17.png

be4f52795afd46c0a0e5b81602ed2944.png

        我们可以清楚的看到,上面的 Debug 模式没有对我们编写的程序进行优化,存放在本地的 exe 文件大小为40KB;而下面的 Release 模式对我们的代码进行了优化,使其缩小为仅仅7KB。这仅仅是一个只有10行不到的代码,就会产生近六倍的差距,我们可以大胆想象一下如果我们的有上百万行,那么程序大小的差异会有多大。

        接着我们来看实际的程序运行结果(上为 Debug 版本,下为 Release 版本):

b03b38e9e4de400da9ac5b0bb4f203e3.png

a240afc626ea4f1dbebff783aaf83c55.png

        我们可以看到,Debug 版本没有优化我们的程序,导致我们写出的 bug 代码原封不动的被执行,在越界访问时造成了程序的死循环;而同样的代码经过 Release 版本的各种优化,我们看到我们的 bug 程序在运行时没有陷入死循环,而是被及时的制止了。 

        最后我们来看看两种版本下的反汇编代码的差异(上为 Debug 版本,下为 Release 版本):

fc213c8b33534bc3aa71047f0c72c93a.png

3214f607f9ca4d9a927509b8013eb6e0.png

        我们可以看到,反汇编代码清晰的展示了两种不同版本下执行的空间、时间效率的差异,显而易见的,Release 版本在优化上远远优于 Debug 版本

        那么既然 Release 版本这么好,我们为什么还要介绍 Debug 版本呢?甚至于说,后文主要就是针对 Debug 版本进行的讲解呢?原因是,★ Debug 模式支持调试而 Release 版本不支持 ★

三、在Windows环境下进行调试:

        1.调试环境的准备:

        首先我们要在环境中选择 Debug 版本,才能使代码正常调试:

e9c240182fe54fa3a97a94e3aab2aaec.png

        2.调试的快捷键:

        在我们的调试过程中,需要用到许多调试功能

d65357bfcf3d412ab8b10bf0eb096fed.jpeg

        为了便于我们更高效的调试,我们有必要记住这些常用的调试快捷键

F5启动调试,常用来跳至下一断点处。

F9创建断点与取消断点。断点的作用为,可以在任意程序语句处打上断点,可以使程序在运行至断点处后暂停执行,便于我们接下来一步一步地执行,方便我们对程序细节进行观查。

F10逐过程。通常用来处理一个过程,一个过程可以是一次函数调用,也可以是一条语句。

F11逐语句。即每次执行一条语句,但是这个快捷键可以使我们的执行逻辑深入到函数内部去(最常用)。

CTRL+F5开始执行而不调试。如果你型让你的程序直接运行起来而不进行调试就可以直接使用。

        3.调试查看程序当前信息:

        ①.查看临时变量的值:

        我们通过 调试 => 窗口 => 监视 ,可以打开监视窗口,在窗口内输入你想要查看的变量名,即可在监视窗口内查看到该临时变量在程序运行时产生的实时变化了(调试状态下):

d11ff952e8ad47de85e2bec555fbd7ce.png

        ②.查看内存信息:

        同样的我们通过 调试 => 窗口 => 内存,可以打开内存窗口,在窗口内输入你想要查看的变量的地址(或取地址操作符+变量名),即可在内存窗口内查看到目标对象的内存使用在程序运行时产生的实时变化了(调试状态下):

0d640f5c55d34d1b845c1b07c3877c77.png

        ③.查看调用堆栈:

        也还是一样,我们通过 调试 => 窗口 => 调用堆栈,可以打开调用堆栈窗口,不同的是该窗口无需输入,会按照当前正在执行的语句位置,反馈出当前程序的堆栈调用情况调试状态下):

6e961633b02a44c3a0e17de5aa5f1870.png

        ④.查看汇编信息:

        我们一般有两种方式去查看汇编信息,第一种是在调试状态下,与上面相同的方式,通过 调试 => 窗口=> 反汇编,打开汇编窗口;而第二种方式是在调试状态下,直接单击鼠标右键,选择转到反汇编,即可打开汇编窗口。这两种方式均可以打开汇编代码窗口,来查看我们写出的代码对应的汇编代码调试状态下):

6fa16dbefade40be9a6b9a0b2b37b348.png

        ⑤.查看寄存器信息:

        通过 调试 => 窗口 => 寄存器,打开寄存器窗口,可以查看当前运行环境的寄存器使用信息调试状态下):

46e93da90035484db92aaf7ee638ac1d.png

四、如何写出好的代码:

        好的代码通常都是易于调试的。优秀的代码通常都具有运行正常bug少效率高可读性高可维护性高注释清晰文档齐全等优点。

        而常用的 coding 技巧主要有使用assert尽可能使用const、使用好的代码注释风格添加必要的代码注释避免编码陷阱等等,再者就取决于程序员自己的亲身代码编写经验了。

        同时各位小伙伴们在编写代码时应当注意,我们在编写程序代码时,要仔细认真的分析参数以及返回值类型的设计尽最大可能避免空指针、野指针对我们程序运行造成的危害等等容易出现错误的地方。再者也就是及时的为我们的代码添加上合适的注释,既便于我们在调试阶段检查我们代码的逻辑性错误,也能大大提高我们代码的可读性与可维护性

        在这里再送给各位小伙伴们一张 “ 没有BUG符 ” ,祝愿各位小伙伴们今后在编写程序代码时:一看就会一写就对没有BUG令人陶醉!

1bc32580d9d64b26bb3c0fa03e6e59be.jpeg

五、编程常见错误:

        1.编译型错误:

        这种类型的错误最为常见,我们可以直接通过查看错误信息提示(双击)解决问题,或凭借我们的代码编写经验,也很容易就能解决,相对来说较为简单。

        2.链接型错误:

        这种类型的错误要稍微难处理一点,我们的处理方法主要是通过查看错误提示信息,在我们的代码中找到错误信息种的标识符,然后逐步调试定位问题所在。这类问题多出现于标识符名、不存在、不符和或存在拼写错误。

        3.运行时错误:

        这类问题最为麻烦,因为它们既在编写语法上没有问题,也不存在拼写错误,而一般常见于我们所编写出来的程序的逻辑漏洞。即看上去没有问题,但在执行时得不出我们想要的执行结果。面对这类问题,我们只能通过借助调试逐步定位问题,慢慢解决。

六、总结:

        到这里,我们关于初阶C语言的学习就全部结束了。在这里我非常感谢各位小伙伴们这么久以来对我的鼓励与支持,每次写到想要放弃时总会有小伙伴私信我为我加油鼓劲。如今我们的学习之旅暂时是告一段落了,不过学习之路还远远没有完结。接下来我会休息几天,调整调整状态,便会开始下一阶段的学习讲解,希望到时候还能看到各位小伙伴们熟的身影。

        希望这些日子写出的一些文字能对各位小伙伴们有所帮助,用心了它们是知识、是力量,不够用心那它们也不过是一堆冰冷的文字罢了。成功是陡峭的阶梯,两手插在裤袋里是爬不上去的,当你想要放弃的时候想想当初为什么坚持到这里!

        新人初来乍到,辛苦各位小伙伴们动动小手,三连走一走 ~ ~ ~  最后,本文仍有许多不足之处,欢迎各位看官老爷随时私信批评指正!

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

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

相关文章

【嵌入式硬件芯片开发笔记】HART调制解调器AD5700芯片配置流程

【嵌入式硬件芯片开发笔记】HART调制解调器AD5700芯片配置流程 低功耗HART调制解调器 适用于AD5700/AD5700-1 我的是XTAL_EN接地&#xff0c;CLK_CFG的两个引脚由同一个GPIO控制 初始时HART_CLK_CFG输出低电平 由RTS引脚控制调制/解调。当RTS处于高电平时&#xff0c;为解调&…

React源码(一): render createElement

React源码——渲染&#xff08;render && createElement&#xff09;的简单实现 前言 当前市面上公司对React需求越来越大主, 对于React的源码学习必须提上日程 初始化项目 React脚手架创建项目 全局安装npm install -g create-react-app创建项目create-react-app M…

Web大学生网页作业成品——仿腾讯游戏官网网站设计与实现(HTML+CSS+JavaScript)

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

常规构件的立面CAD图案绘制

今天绘制的这个常规构件CAD立面图形呢&#xff0c;用到的都是很基础的CAD命令&#xff0c;有直线、修剪、倒角和旋转等&#xff0c;绘制出来也是很简单的&#xff0c;可以跟着一起操作一下 目标对象 操作步骤 1.使用直线命令绘制出一下线段&#xff0c;形成一个封闭图形 2.用…

【Windows基础】本地安全策略

本地安全策略基本内容 概念 对登陆到计算机上的账号定义一些安全设置&#xff0c;在没有活动目录集中管理的情况下&#xff0c;本地管理员必须为计算机进行设置以确保其安全。 主要是对登录到计算机得账户进行一些安全设置主要影响是本地计算机安全设置 打开方式 三种方式&…

python的distutils、setuptools模块

python中安装包的方式有很多种&#xff1a; 源码包&#xff1a;python setup.py install在线安装&#xff1a;pip install 包名&#xff08;linux&#xff09; / easy_install 包名(window) python包在开发中十分常见&#xff0c;一般的使用套路是所有的功能做一个python模块包…

一个bug,干倒一家估值1.6亿美元的公司

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注&#xff01; 动态类型一时爽&#xff0c;代码重构火葬场。 ——题记 你生涯中写过的最严重的bug是什么&#xff1f; 我们日常接触的bug&#xff0c;无非是页面崩溃&a…

【Zookeeper】学习笔记(一)

Zookeeper学习笔记一、概述1.1、Zookeeper1.2、Zookeeper工作机制1.3、Zookeeper特点1.4、数据结构1.6、应用场景1.6.1、统一命名服务1.6.2、统一配置管理1.6.3、统一集群管理1.6.4、服务器动态上下线1.6.5、软负载均衡二、下载安装2.1、集群规划2.1、集群规部署三、zk选举3.1、…

A-Level商务例题解析及练习

今日知识点&#xff1a; Marketing mix Place Price Promotion Product例题 Q: Discuss the best ways a car manufacturer could use the marketing mix to increase its share of the market. (20)解析 Answers could include: Marketing mix as a framework/process for ide…

基于RFID的物流智能仓储系统的研究(基于STM32的智能仓储系统)

提示&#xff1a;记录做的毕设 文章目录前言一、功能要求:二、代码思路三、硬件说明四、部分代码以及框图等资料五、联系我喜欢请点赞哦&#xff01;前言 随着经济的发展&#xff0c;对企业的生产经营要求提高&#xff0c;企业必须综合利用各种先进技术&#xff0c;在网络与信…

VUE3 响应式 API 之 toRef 与 toRefs

相信各位开发者看到这里时&#xff0c;应该已经对 ref 和 reactive API 都有所了解了&#xff0c;为了方便开发者使用&#xff0c; Vue 3 还推出了两个与之相关的 API &#xff1a; toRef 和 toRefs &#xff0c;都是用于 reactive 向 ref 转换。 各自的作用 这两个 API 在拼写…

Java安全--CC1的补充和CC6

CC1的补充 上一次讲的是cc链的一种形式&#xff0c;这个补充的cc链子是yso的cc链。 这个链子确实比较麻烦&#xff0c;但是和我们下一步要学习的cc6有比较紧的联系。所以做一下补充&#xff0c;值得一提的是这个链子也确实很巧妙 我们看一下两条链子的分歧在哪里&#xff1a; 从…

[附源码]Python计算机毕业设计Django影评网站系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

在地图上基于OpenLayers实现点/线/面静态的绘制显示

在做GIS相关的工作过程中&#xff0c;是离不开矢量的数据的。矢量作为最基础的数据形式&#xff0c;一般通用在各个项目中。在导航软件开发或者应用中&#xff0c;点/线/面的标记&#xff0c;标绘&#xff0c;显示等都是不可缺少的。本文主要是来介绍在地图上基于OpenLayers实现…

Qt-数据库开发-QTableView操作数据库(2)

Qt-数据库开发-QTableView操作数据库、自增Key 文章目录Qt-数据库开发-QTableView操作数据库、自增Key1、概述2、实现效果3、主要代码4、完整源代码更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;数据库开发 &#x1f448; 1、概述 在开发数据库开发时…

40 | Linux安装node.js

1 环境准备 系统为ubuntu系统 2 下载压缩包 2.1 参考地址&#xff1a; https://nodejs.org/zh-cn/download/releases/2.2 创建文件夹 mkdir software wget https://nodejs.org/download/release/v16.18.0/node-v16.18.0-linux-x64.tar.gz2.3 解压 2.3.1 解压二进制文件…

docker——对镜像的操控笔记

一:镜像在哪里 这个问题问到点子上了,就好像说肉好吃,那你告诉我哪里才能买的到? 1. docker官方渠道 docker官方有一个 Docker Hub 网址,你能想到和想不到的镜像这上面都有,比如web开发者熟悉的nginx,redis,mongodb等等,而且还告诉 你怎么去下载,如下图: 接下来你可…

【Zookeeper】学习笔记(二)

Zookeeper学习笔记四、客户端命令4.1、新增节点4.2、查询节点信息4.3、节点类型4.4、更新节点4.5、删除节点4.6、监听器五、SpringBOOT整合Zookeeper六、写数据流程6.1、写流程之写入请求直接发送给Leader节点6.2、写流程之写入请求发送给follower节点七、服务器动态上下线监听…

Matlab 中 global 函数实例解析

目录 global 函数 案例分析 1 案例分析 2 使用golbal的优点 1. 传递大数据的参数 2. 过多的常量需要传递 global 函数 比如在主函数里面&#xff0c;你需要设置 Nc 这个变量是一个全局变量&#xff0c;就需要声明一下&#xff1a; global Nc; 然后在子函数里面你又用到了…

EMQX 多版本发布、新增自定义函数功能

11 月&#xff0c;EMQX 开源版和企业版分别发布了多个迭代版本&#xff0c;在安全性保障和生态集成方面又有了新的提升。 MQTT 消息云服务 EMQX Cloud 推出了新功能——自定义函数&#xff0c;用户可以更方便地将 IoT 数据处理为符合数据流的数据格式。 EMQX 11 月 EMQX 开源…