实用调试技巧(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 办公软件,实行通用化产品设计,充分贴合企业管理需求,本着简洁易用、高效智能的原则,为企业快速打造移动化、无纸化、数字化的办公平台。 该漏洞是由于存在…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...