实用调试技巧(2)
文章目录
- 6. 如何写出好(易于调试)的代码
- 6.1 优秀的代码:
- 6.2 示范:
- 6.3 const的作用
- 7. 编程常见的错误
- 7.1 编译型错误
- 7.2 链接型错误
- 7.3 运行时错误
- 附:
6. 如何写出好(易于调试)的代码
6.1 优秀的代码:
- 代码运行正常
- bug很少
- 效率高
- 可读性高
- 可维护性高
- 注释清晰
- 文档齐全
常见的coding技巧:
- 使用assert
- 尽量使用const
- 养成良好的编码风格
- 添加必要的注释
- 避免编码的陷阱
6.2 示范:
模拟实现库函数:strcpy
我们先来看一下strcpy是如何使用的:
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "hello bit";char arr2[20] = "xxxxxxxxxxxxx";//strcpy(arr2, arr1);//printf("%s\n", arr2);printf("%s\n", strcpy(arr2, arr1));return 0;
}
接下来我们来实现它:
#include <stdio.h>void my_strcpy(char* dest, char* src)
{while (*src != '\0'){*dest = *src;dest++;src++;}*dest = *src;// \0 的拷贝
}int main()
{char arr1[] = "hello bit";char arr2[20] = "xxxxxxxxxxxxx";my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}
我们还可以使用assert对它进行优化:
#include <stdio.h>
#include <assert.h>void my_strcpy(char* dest, char* src)
{//断言assert(dest != NULL);assert(src != NULL);while (*src != '\0'){*dest = *src;dest++;src++;}*dest = *src;// \0 的拷贝
}int main()
{char arr1[] = "hello bit";char arr2[20] = "xxxxxxxxxxxxx";char* p = NULL;//my_strcpy(p, arr1);my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}
通过assert,我们可以确保某些事情不会发生,一旦发生,它就会报错,这样就能方便我们快速找到错误。
我们还可以将字符和\0的拷贝放到一起:
#include <stdio.h>
#include <assert.h>void my_strcpy(char* dest, char* src)
{//断言assert(dest != NULL);assert(src != NULL);while (*dest = *src)//赋值表达式,比如把h赋给*dest,表达式的结果就是h的ASCII码值{dest++;src++;}}int main()
{char arr1[] = "hello bit";char arr2[20] = "xxxxxxxxxxxxx";char* p = NULL;//my_strcpy(p, arr1);my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}
还可以这样写:
#include <stdio.h>
#include <assert.h>void my_strcpy(char* dest, char* src)
{//断言assert(dest != NULL);assert(src != NULL);while (*dest++ = *src++)//赋值表达式,比如把h赋给*dest,表达式的结果就是h的ASCII码值{;//空语句}}int main()
{char arr1[] = "hello bit";char arr2[20] = "xxxxxxxxxxxxx";char* p = NULL;//my_strcpy(p, arr1);my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}
此外,我们还可以对返回类型进行优化:
#include <stdio.h>
#include <assert.h>//函数返回的是目标空间的起始地址
char* my_strcpy(char* dest, char* src)
{char* ret = dest;//断言assert(dest != NULL);assert(src != NULL);while (*dest++ = *src++)// 赋值表达式,比如把h赋给*dest,表达式的结果就是h的ASCII码值{;//空语句}return ret;
}int main()
{char arr1[] = "hello bit";char arr2[20] = "xxxxxxxxxxxxx";char* p = NULL;//my_strcpy(p, arr1);//my_strcpy(arr2, arr1);//printf("%s\n", arr2);printf("%s\n", my_strcpy(arr2, arr1));return 0;
}
另外,为了保证传进去的arr1不被修改,我们还可以加上const进行修饰:
#include <stdio.h>
#include <assert.h>//函数返回的是目标空间的起始地址
char* my_strcpy(char* dest, const char* src)
{char* ret = dest;//断言assert(dest != NULL);assert(src != NULL);while (*dest++ = *src++)// 赋值表达式,比如把h赋给*dest,表达式的结果就是h的ASCII码值{;//空语句}return ret;
}int main()
{char arr1[] = "hello bit";char arr2[20] = "xxxxxxxxxxxxx";char* p = NULL;//my_strcpy(p, arr1);//my_strcpy(arr2, arr1);//printf("%s\n", arr2);printf("%s\n", my_strcpy(arr2, arr1));return 0;
}
6.3 const的作用
有以下两种方式可以修改num的值:
int main()
{int num = 10;num = 20;int* p = #*p = 200;return 0;
}
现在我们加上const:
#include <stdio.h>int main()
{const int n = 100;//n = 200;//errint* p = &n;*p = 20;printf("%d\n", n);return 0;
}
加上const是为了不让n的值发生变化,但是现在我们却可以通过地址的方式来改变它,于是我们可以进行以下操作:
int main()
{const int n = 100;//n = 200;//err//int* p = &n;//*p = 20;//printf("%d\n", n);const int* p = &n;//*p = 20;//errreturn 0;
}
通过以上代码我们可以发现const是可以修饰指针的:
//const 修饰指针的时候
//当const 放在*的左边的时候,限制的是指针指向的内容,不能通过指针变量改变指针指向的内容,但是指针变量本身是可以改变的
//当const 放在*的右边的时候,限制的是指针变量本身,指针变量本身是不能改变的,但是指针指向的内容是可以通过指针来改变的#include <stdio.h>int main()
{int m = 10;int n = 100;//const可以修饰指针const int* p = &m;//*p = 0;//errp = &n;//okprintf("%d\n", m);return 0;
}
#include <stdio.h>int main()
{int m = 10;int n = 100;//const可以修饰指针int* const p = &m;*p = 0;//ok//p = &n;//errprintf("%d\n", m);return 0;
}
#include <stdio.h>int main()
{int m = 10;int n = 100;//const可以修饰指针const int* const p = &m;//*p = 0;//err//p = &n;//errprintf("%d\n", m);return 0;
}
练习:
模拟实现一个strlen函数
//模拟实现一个strlen函数
//assert
//const//size_t 是专门为sizeof设计的一个类型
//size_t --> unsigned int / unsigned long
//>=0#include <stdio.h>
#include <assert.h>size_t my_strlen(const char* str)
{assert(str != NULL);size_t count = 0;while (*str != '\0'){count++;str++;}return count;
}int main()
{char arr[] = "abc";size_t len = my_strlen(arr);printf("%zd\n", len);//zd是专门用来打印size_t类型的值的return 0;
}//%u 无符号整数的
7. 编程常见的错误
7.1 编译型错误
直接看错误提示信息(双击),解决问题,或者凭借经验就可以搞定,相对来说简单。
int main()
{int a = 10//编译期间找到的一般都是语法问题return 0;
}
7.2 链接型错误
看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在,一般是标识符名不
存在或者拼写错误。
//链接型错误是在链接期间发现的错误int Add(int x, int y)
{return x + y;
}int main()
{int ret = add(2, 3);return 0;
}
7.3 运行时错误
借助调试,逐步定位问题,最难搞。
#include <stdio.h>int Add(int x, int y)
{return x - y;
}int main()
{int ret = Add(2, 3);printf("%d\n", ret);return 0;
}
附:
实用调试技巧(1)
相关文章:
实用调试技巧(2)
文章目录 6. 如何写出好(易于调试)的代码6.1 优秀的代码:6.2 示范:6.3 const的作用 7. 编程常见的错误7.1 编译型错误7.2 链接型错误7.3 运行时错误 附: 6. 如何写出好(易于调试)的代码 6.1 优…...
海外ASO优化之如何优化游戏应用
如果我们发布了一款手机游戏或者管理了一款手机游戏,那么需要确保我们的手机游戏对合适的人可见,目的是增加应用的下载量。 1、优化游戏元数据的关键词。 Apple和Google在应用商店中为我们提供有限的空间,来描述手机游戏及其优势。我们需要使…...
SpringMVC: Java Web应用开发的框架之选
引言 在当今的软件开发领域中,Web应用的需求不断增长。为了满足这种需求,各种Web框架应运而生。其中,SpringMVC作为一种优秀的Java Web框架,受到广泛关注和使用。本文将以文章的形式给您讲解SpringMVC的重要概念、工作原理和核心…...
【华为设备升级】AR路由器升级设备软件示例
升级设备软件示例 通过介绍设备升级的具体步骤,帮助用户顺利完成系统设备升级。 组网需求 设备当前系统软件版本已经不能满足用户需要,用户需要更大的规格和部署更多的特性,此时用户需要对系统软件进行升级。 如图1所示,网络中的某…...
Dataset 的一些 Java api 操作
文章目录 一、使用 Java API 和 JavaRDD<Row> 在 Spark SQL 中向数据帧添加新列二、foreachPartition 遍历 Dataset三、Dataset 自定义 Partitioner四、Dataset 重分区并且获取分区数 一、使用 Java API 和 JavaRDD 在 Spark SQL 中向数据帧添加新列 在应用 mapPartition…...
Vue + Element UI 前端篇(十一):第三方图标库
Vue Element UI 实现权限管理系统 前端篇(十一):第三方图标库 使用第三方图标库 用过Elment的同鞋都知道,Element UI提供的字体图符少之又少,实在是不够用啊,幸好现在有不少丰富的第三方图标库可用&…...
HDFS:Hadoop文件系统(HDFS)
Hadoop文件系统(HDFS)是一个分布式文件系统,主要用于存储和处理大规模的数据集。HDFS是Apache Hadoop的核心组件之一,能够支持上千个节点的集群,并能够处理PB级别的数据。 HDFS将大文件切割成小的数据块(默…...
SpringMvc--综合案例
目录 1.SpringMvc的常用注解 2.参数传递 基础类型(String) 创建一个paramController类: 创建一个index.jsp 测试结果 复杂方式 编辑 测试结果 RequestParam 测试结果 PathVariable 测试结果 RequestBody pom.xml依赖导入 输…...
工业4.0时代生产系统对接集成优势,MES和ERP专业一体化管理-亿发
在现代制造业中,市场变化都在不断加速。企业面临着不断加强生产效率、生产质量和快速适应市场需求的挑战。在制造行业,日常管理中的ERP系统、MES系统就显得尤为重要。越来越多的企业正在采用MES系统和ERP管理系统的融合,以实现智能化生产管理…...
IT运维监控系统和网络运维一样吗
IT运维监控系统和网络运维不是一样的。IT运维监控系统是一系列IT管理产品的统称,它所包含的产品功能强大、易于使用、解决方案齐全,可一站式满足用户的各种IT管理需求。而网络运维是指对网络设备进行监控、维护和管理,包括硬件故障的排除、软…...
c语言flag的使用
flag在c语言中标识某种状态或记录某种信息,可以通过修改flag中来控制程序流程,判断某种状态是否存在或记录某种信息 操作:(1)初始化 (2)赋值 (3)判断 (4)修改 (5)去初始化 #include <stdlib.h>int power_state_check;int main() {int i 0;power_state_check…...
docker push image harbor http 镜像
前言 搭建的 harbor 仓库为 http 协议,在本地登录后,推送镜像发生如下报错: docker push 192.168.xx.xx/test/grafana:v10.1.1 The push refers to repository [192.168.xx.xx/test/grafana] Get "https://192.168.xx.xx/v2/": dia…...
羊城杯2023 部分wp
目录 D0nt pl4y g4m3!!!(php7.4.21源码泄露&pop链构造) Serpent(pickle反序列化&python提权) ArkNights(环境变量泄露) Ez_misc(win10sinpping_tools恢复) D0nt pl4y g4m3!!!(php7.4.21源码泄露&pop链构造) 访问/p0p.php 跳转到了游戏界面 应该是存在302跳转…...
解读Java对Execl读取数据
1.读取execl文件路径,或者打开execl // 初始化文件流FileInputStream in = null;in = new FileInputStream(new File(path));workbook = new XSSFWorkbook(in);sheet = workbook.getSheetAt(0);rows = sheet.getPhysicalNumberOfRows(); 2.读取execl中sheet页数,即获取当前E…...
RHCE——十七、文本搜索工具-grep、正则表达式
RHCE 一、文本搜索工具--grep1、作用2、格式3、参数4、注意5、示例5.1 操作对象文件:/etc/passwd5.2 grep过滤命令示例 二、正则表达式1、概念2、基本正则表达式2.1 常见元字符2.2 POSIX字符类2.3 示例 3、扩展正则表达式3.1 概念3.2 示例 三、作业1、作业一2、作业…...
小程序实现摄像头拍照 + 水印绘制
文章标题 01 功能说明02 使用方式 & 效果图2.1 基础用法2.2 拍照 底部定点水印 预览2.3 拍照 整体背景水印 预览 03 全部代码3.1 页面布局 html3.2 业务核心 js3.3 基础样式 css 01 功能说明 需求:小程序端需要调用前置摄像头进行拍照,并且将拍…...
SpringMVC:从入门到精通,7篇系列篇带你全面掌握--三.使用SpringMVC完成增删改查
🥳🥳Welcome Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于SpringMVC的相关操作吧 目录 🥳🥳Welcome Huihuis Code World ! !🥳🥳 效果演示 一.导入项目的相关依赖 二.…...
ABAP GN_DELIVERY_CREATE 报错 VL 561
GN_DELIVERY_CREATE 去创建内向交货单的时候。 报错 VL 561 Essential transfer parameters are missing in record 表示一些必输字段没输入 诸如一些,物料号。单位。等一些字段 输入之后即可 DATA: ls_return TYPE bapireturn.DATA: lt_return TYPE STANDARD T…...
AWS-数据库迁移工具DMS-场景:单账号跨区域迁移RDS for Mysql
参考文档: 分为几个环节: 要使用 AWS DMS 迁移至 Amazon RDS 数据库实例: 1.创建复制实例 有坑内存必须8g或者以上,我测试空库 都提示内存不足 2.创建目标和源终端节点 目标空库也得自己创建哈 3.刷新源终端节点架构 4.创建迁…...
【漏洞复现】E-office文件包含漏洞
漏洞描述 Weaver E-Office是中国泛微科技(Weaver)公司的一个协同办公系统。泛微 E-Office 是一款标准化的协同 OA 办公软件,实行通用化产品设计,充分贴合企业管理需求,本着简洁易用、高效智能的原则,为企业快速打造移动化、无纸化、数字化的办公平台。 该漏洞是由于存在…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...
客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...
海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...
GraphRAG优化新思路-开源的ROGRAG框架
目前的如微软开源的GraphRAG的工作流程都较为复杂,难以孤立地评估各个组件的贡献,传统的检索方法在处理复杂推理任务时可能不够有效,特别是在需要理解实体间关系或多跳知识的情况下。先说结论,看完后感觉这个框架性能上不会比Grap…...
深入理解 React 样式方案
React 的样式方案较多,在应用开发初期,开发者需要根据项目业务具体情况选择对应样式方案。React 样式方案主要有: 1. 内联样式 2. module css 3. css in js 4. tailwind css 这些方案中,均有各自的优势和缺点。 1. 方案优劣势 1. 内联样式: 简单直观,适合动态样式和…...
