当前位置: 首页 > news >正文

初阶C语言——实用调试技巧【详解】

文章目录

  • 1. 什么是bug?
  • 2. 调试是什么?有多重要?
    • 2.1 调试是什么?
    • 2.2 调试的基本步骤
    • 2.3 Debug和Release的介绍
  • 3.学会使用快捷键
  • 4.调试的时候查看程序当前信息
    • 4.1 查看临时变量的值
    • 4.2 查看内存信息
    • 4.3 查看调用堆栈
    • 4.4 查看汇编信息
    • 4.5 查看寄存器信息
  • 5. 一些调试的实例
    • 5.1 实例一
    • 5.2 实例二
    • 5.3 大代码如何调试
  • 6. 如何写出好(易于调试)的代码
    • 6.1 优秀的代码:
    • 6.2 示范
    • 6.3 const的作用
  • 7. 编程常见的错误

1. 什么是bug?

bug是计算机领域专业术语,原意是臭虫。现在用来指代计算机上存在的漏洞。

2. 调试是什么?有多重要?

所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有愧,就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺藤而上,这就是推理的途径。
顺着这条途径顺流而下就是犯罪,逆流而上,就是真相。

一名优秀的程序员是一名出色的侦探。

2.1 调试是什么?

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

2.2 调试的基本步骤

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

2.3 Debug和Release的介绍

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

代码:

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

上述代码在Debug环境的结果展示:
在这里插入图片描述
上述代码在Release环境的结果展示:
在这里插入图片描述
在环境中选择 debug 选项,才能使代码正常调试。

3.学会使用快捷键

在这里插入图片描述
最常使用的几个快捷键:
F5

启动调试,经常用来直接跳到下一个断点处。

F9

创建断点和取消断点
断点的重要作用,可以在程序的任意位置设置断点。 这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。

F10

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

F11

逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最长用的)。

CTRL + F5

开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用

Fn

辅助功能键

如果一个代码循环一千多次,而我们认为他的错误在四百次的地方时,要怎么调试?
这时我们就可以给他加一个触发断点的条件,或者使用一个if语句来进行判断。如下图所示:
在这里插入图片描述
在这里插入图片描述

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

通过调试下的窗口键来进行查看
在这里插入图片描述

4.1 查看临时变量的值

在调试开始之后,用于观察变量的值。
在这里插入图片描述

4.2 查看内存信息

在调试开始之后,用于观察内存信息。
在这里插入图片描述
显示内存结果:
在这里插入图片描述

4.3 查看调用堆栈

栈:
只能从顶上放入,再从顶上删除
在这里插入图片描述

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

4.4 查看汇编信息

在这里插入图片描述
可以切换到汇编代码。

4.5 查看寄存器信息

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

5. 一些调试的实例

5.1 实例一

实现代码:求 1!+2!+3! …+ n! ;不考虑溢出。

#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;for (j = 1; j <= i; j++){ret *= j;}sum += ret;}printf("%d\n", sum);return 0;
}

这时候我们如果3,期待输出9,但实际输出的是15
这时候我们就得通过调试找我们问题。
在这里插入图片描述

通过调试,我们发现问题出现在ret的值上,ret的值为每次结果值的累积效果,所以在循环内部令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++){ret = 1;int j = 0;for (j = 1; j <= i; j++){ret *= j;}sum += ret;}printf("%d\n", sum);return 0;
}

运行结果:
在这里插入图片描述

5.2 实例二

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

在这里插入图片描述
数组越界访问,我们发现程序并不会崩溃而是陷入死循环,这是为什么呢?
在这里插入图片描述
通过调试我们发现arr[12]与i的地址一样,改变arr[12]就改变了i
在这里插入图片描述

arr与i之间到底空几个空间取决于编译器的内存分配
vc6.0 中间没有空间
gcc 中间空一个整形
vs 中间空两个整形

注: 这个代码的运行结果是和环境相关的!

5.3 大代码如何调试

在这里插入图片描述
例如我们写过的三子棋,当出现问题时,我们可以在感觉有问题的模块放上断点来进行调试。

6. 如何写出好(易于调试)的代码

6.1 优秀的代码:

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

常见的coding技巧:

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

6.2 示范

模拟实现库函数:strcpy
strcpy
string copy —— 字符串拷贝

在这里插入图片描述
代码演示:

#include <stdio.h>
#include <assert.h>
//strcpy函数返回的是目标空间的起始地址char* my_strcpy(char* dest, const char* src)
{//断言 - 保证指针的有效性assert(dest && src);char* ret = dest;//把src指向的字符串拷贝到dest指向是的数组空间,包括\0字符while (*dest++ = *src++){;}return ret;
}int main()
{char arr1[] = "hello world";char arr2[20] = { 0 };//链式访问printf("%s\n", my_strcpy(arr2, arr1));return 0;
}

6.3 const的作用

代码演示:

#include <stdio.h>
//代码1
void test1()
{int n = 10;int m = 20;int* p = &n;*p = 20;//ok?p = &m; //ok?printf("%d\n", m);
}
void test2()
{//代码2int n = 10;int m = 20;const int* p = &n;p = &m; //ok//*p = 20;//noprintf("%d\n", m);
}
void test3()
{int n = 10;int m = 20;int* const p = &n;*p = 20; //ok//p = &m; //noprintf("%d\n", m);
}
int main()
{//测试无cosnt的test1();//测试const放在*的左边test2();//测试const放在*的右边test3();return 0;
}

结论:
const修饰指针变量的时候:

  1. const 放在*的左边, *p不能改了,也就是p指向的内容,不能通过p来改变了。但是p是可以改变的,p可以指向其他的变量
  2. const 放在的右边,限制的是p,p不能改变,但是p指向的内容p,是可以通过p来改变的

练习:

模拟实现一个strlen函数
参考代码:

#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{int count = 0;assert(str != NULL);while (*str)//判断字符串是否结束{count++;str++;}return count;
}
int main()
{const char* p = "abc";//测试int len = my_strlen(p);//strlen函数求\0之前字符串的长度printf("len = %d\n", len);return 0;
}

7. 编程常见的错误

1.编译型错误

接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。

例如语句后的分号
在这里插入图片描述

2. 链接型错误

看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不
存在或者拼写错误。

例如:
在这里插入图片描述

3.运行时错误

借助调试,逐步定位问题。最难搞。

关于调试技巧的讲解七七就分享到这了,有什么问题或者需要改进的地方欢迎评论区留言,或者私信都可以哦!

相关文章:

初阶C语言——实用调试技巧【详解】

文章目录1. 什么是bug&#xff1f;2. 调试是什么&#xff1f;有多重要&#xff1f;2.1 调试是什么&#xff1f;2.2 调试的基本步骤2.3 Debug和Release的介绍3.学会使用快捷键4.调试的时候查看程序当前信息4.1 查看临时变量的值4.2 查看内存信息4.3 查看调用堆栈4.4 查看汇编信息…...

Android 绘图基础:Canvas画布——自定义View基础(绘制表盘、矩形、圆形、弧、渐变)

Canvas画布&#xff0c;通过它我们可以自定义一个View&#xff0c;设置View的相关效果之类的。感觉用法差不多&#xff0c;重要的是要理解方法中传入的参数的含义&#xff0c;比如float类型的参数&#xff0c;传递的是坐标,已开是没有注意传入的参数时坐标&#xff0c;导致我迷…...

js拷贝数组对象:浅拷贝深拷贝

前言 js拷贝数组对象&#xff1a;浅拷贝&深拷贝&#xff0c;包括&#xff1a;Object.assign、concat、slice、JSON.parse(JSON.stringify()) 场景&#xff1a;弹窗选择组织结构&#xff08;树形结构&#xff09;&#xff0c;选择后显示相关数据至输入框中&#xff08;每次选…...

【C++】string类的使用

目录 一、标准库中的string类 二、string类的常用接口 1、string类对象的常见构造 2、string类对象的容量操作 2.1、size 与 length 2.2、capacity 与 reserve 2.3、resize 2.4、总结 3、string类对象的访问及遍历操作 3.1、operator[] 与 at 3.2、begin end 3.3、…...

微服务架构简介

微服务 软件架构是一个包含各种组织的系统组织&#xff0c;这些组件包括 Web服务器, 应用服务器, 数据库,存储, 通讯层), 它们彼此或和环境存在关系。系统架构的目标是解决利益相关者的关注点。 image Conway’s law: Organizations which design systems[...] are constrained…...

【Spring源码】AOP的开端:核心对象创建的准备工作

AOP的核心成员是如何被被加载的&#xff1f;本篇我们主要分析使用xml的逻辑&#xff0c;如果使用注解&#xff0c;增加注解处理类即可&#xff08;ConfigurationClassPostProcessor&#xff09;拿之前分析循环的时候举的例子&#x1f330;&#xff0c;它的日志切面就是通过xml进…...

新号涨粉22w,搞笑博主再次爆火,小红书近期创作趋势是什么?

2月借势元宵、情人节&#xff0c;小红书平台又涌现出哪些黑马博主&#xff1f;品牌在投放种草方面有何亮眼表现&#xff1f;为洞察小红书平台的内容创作趋势及品牌营销策略&#xff0c;新红推出2月月度榜单&#xff0c;从创作者及品牌两方面入手&#xff0c;解析月榜数据&#…...

【C++】30h速成C++从入门到精通(内存管理、函数/类模板)

C内存分布我们先来看一下下面的一段代码相关问题int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";char* pChar3 "abcd";int* ptr1 (int*)mal…...

自动驾驶决策概况

文章目录1. 第一章行为决策在自动驾驶系统架构中的位置2. 行为决策算法的种类2.1 基于规则的决策算法2.1.1 决策树2.1.2 有限状态机&#xff08;FSM&#xff09;2.1.3 基于本体论&#xff08;Ontologies-based&#xff09;2.2 基于统计的决策算法2.2.1 贝叶斯网络&#xff08;B…...

金山轻维表项目进展自动通知

项目经理作为项目全局把控者&#xff0c;经常要和时间“赛跑”。需要实时了解到目前进展如何&#xff0c;跟进人是那些&#xff1f;哪些事项还未完成&#xff1f;项目整体会不会逾期&#xff1f;特别是在一些大型公司中&#xff0c;优秀的项目经理已经学会使用金山轻维表做项目…...

基于上下文分析的 Python 实时 API 推荐

原文来自微信公众号“编程语言Lab”&#xff1a;基于上下文分析的 Python 实时 API 推荐 搜索关注 “编程语言Lab”公众号&#xff08;HW-PLLab&#xff09;获取更多技术内容&#xff01; 欢迎加入 编程语言社区 SIG-程序分析 参与交流讨论&#xff08;加入方式&#xff1a;添加…...

软件测试-接口测试-代码实现接口测试

文章目录 1.request1.1 request介绍1.2 发送get请求1.3 发送set请求1.4 其他请求方式1.5 传递url参数1.6 响应内容解析1.7 cookie1.8 设置session2.集成UnitTest2.1 接口测试框架开发2.2 案例:使用TPShop项目完成对登录功能的接口测试1.request 1.1 request介绍 概念 基于py…...

中村成洋《垃圾回收的算法与实现》PDF 读书笔记

观前提醒 为了能够锻炼自己&#xff0c;我会查阅大量外文不停的修改内容&#xff0c;少部分会提示成中文。 可能有误&#xff0c;请见谅 提示&#xff1a;若是觉得阅读困难&#xff0c;可以看如下内容 脚本之家可获取&#xff0c;若失效可私信浏览器的沙拉查词扩展&#xf…...

docker 网络模式

docker 网络模式主要分为四种&#xff0c;可以通过docker network ls 查看 ~$ docker network ls NETWORK ID NAME DRIVER SCOPE a51d97d72f10 bridge br…...

数据库开发(一文概括mysql基本知识)

Mysql 是最流行的关系型数据库管理系统&#xff0c;在 WEB 应用方面 MySQL 是最好的 关系型数据库(Relational Database Management System&#xff1a;关系数据库管理系统)应用软件之一。mysql在问开发中&#xff0c;几乎必不可少&#xff0c;因为其他的可能是要收费的&#x…...

【JVM】详解Java内存区域和分配

这里写目录标题一、前言二、运行时数据分区2.1程序计数器(PC)2.2 Java虚拟机栈2.3 本地方法栈2.4 Java堆2.5 方法区2.5.1 运行时常量池2.6 直接内存三、HotSpot虚拟机对象探秘3.1 对象的创建3.2 对象的内存布局3.3 对象的访问定位一、前言 C/C需要自行回收和释放已经没用的对象…...

JAVA开发(史上最完整追本溯源JAVA历史、发展和学习)

(第二次世界大战1931-1945) 世界上最先进的技术往往是由于战争催生&#xff0c;在第二次世界大战中除了飞机&#xff0c;坦克和大炮的武器较量外&#xff0c;在隐秘战线的情报工作其实更为重要&#xff0c;在军队将领来往的电报中&#xff0c;为了防止军事情报的泄漏&#xff…...

Qt 防止程序退出

文章目录摘要QWidgetQML方法 1方法 2关键字&#xff1a; Qt、 eventFilter、 Close、 键盘、 任务管理器摘要 今天要聊得内容还是怎么防止别人关闭我的程序&#xff0c;之前都是在win下面&#xff0c;一般都是用过钩子连捕获键盘事件&#xff0c;完了吧对应的事件忽略&#x…...

【校验码 - 循环冗余校验码CRC】

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 目录 循环冗余校验码 1.多项式 2.CRC编码的组成 3.校验码的生成 4.例题&#xff1a; 循环冗余校验码 广泛地在网络通信及磁盘存储时采用。 1.多项式 在循环冗余校验(CRC)码中&#xff0c;无一例…...

【Rust】一文讲透Rust中的PartialEq和Eq

前言 本文将围绕对象&#xff1a;PartialEq和Eq&#xff0c;以及PartialOrd和Ord&#xff0c;即四个Rust中重点的Compare Trait进行讨论并解释其中的细节&#xff0c;内容涵盖理论以及代码实现。 在正式介绍PartialEq和Eq、以及PartialOrd和Ord之前&#xff0c;本文会首先介绍…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...

智能职业发展系统:AI驱动的职业规划平台技术解析

智能职业发展系统&#xff1a;AI驱动的职业规划平台技术解析 引言&#xff1a;数字时代的职业革命 在当今瞬息万变的就业市场中&#xff0c;传统的职业规划方法已无法满足个人和企业的需求。据统计&#xff0c;全球每年有超过2亿人面临职业转型困境&#xff0c;而企业也因此遭…...