【C语言】超详解strncpystrncatstrncmpstrerrorperror的使⽤和模拟实现
🌈write in front :🔍个人主页 : @啊森要自信的主页
✏️真正相信奇迹的家伙,本身和奇迹一样了不起啊!
欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助,如有错误,可以指出,让我们一起探讨学习交流,一起加油鸭。
文章目录
- 📝前言
- 🌠 库函数strncpy
- 🌉strncpy 模拟实现
- 🌠strncat 函数的使⽤
- 🌉strncat 模拟实现
- 🌠strncmp函数的使⽤
- 🌉strncmp模拟实现
- 🌠strerror
- 🌉 perror
- 🚩总结
📝前言
本小节,阿森继续和你一起学习5个字符串函数:strncpy,strcnat,strncmp的使用和两种模拟实现方法,他们和strcpy等函数比较多了一个n ,实现方法有很大区别,还有strerror和perror的使用,学习这些库函数,可以更好的方便操作字符和字符串,文章干货满满,接下来我们就学习一下这些函数吧!
strcpy、strcat这类函数不安全,因为它们在复制字符串时不检查目标缓冲区的大小,可能会导致缓冲区溢出。
而strncpy、strncat、strncmp这类函数相对来说更安全,因为它们在复制/追加字符串时会限定最大长度参数n,避免无限制地写入目标缓冲区。
点击—>手把手教你配置VS的常见函数如何不报错!

🌠 库函数strncpy
strncpy函数用于将一个字符串拷贝到另一个字符串中,可以限定拷贝的字符数。
函数原型:
char * strncpy ( char * destination, const char * source, size_t num );dest - 目标字符串,用于接收拷贝内容。src - 源字符串,从中拷贝内容。 num - 要拷贝的字符数。
返回值:
返回目标字符串dest的指针。
注意点:
-
检查
dest空间是否足以容纳src的n个字符及结尾'\0'。strncpy不会检查dest的长度,如果dest空间不足可能会导致缓冲区溢出。 -
拷⻉
num个字符从源字符串到⽬标空间。拷贝num个就num个,不会拷贝多,也不会自己添加\0。

-
如果源字符串的⻓度⼩于
num,则拷⻉完源字符串之后,在⽬标的后边追加0,直到num个。

例子:
# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{char str1[] = "Hello World";char str2[7];str2[5] = '\0';strncpy(str2, str1, 5);printf("str1: %s\n", str1);printf("str2: %s\n", str2);return 0;
}
输出:
str1: Hello World
str2: Hello
🌉strncpy 模拟实现
对于strncpy函数,阿森给你带来了两种模拟实现方法,详解如下:
- 主函数(两种模拟实现都可以用这个进行测试)
int main()
{char dest[20]="xxxxxxxxxxxxxxxxx";char src[] = "hello";size_t set = strlen(src);printf("%d\n", set);my_strncpy(dest, src, 3);printf("%s\n", dest);my_strncpy(dest, src, 9);printf("%s\n", dest);return 0;
}
- 用数组模拟实现
char* my_strncpy(char* dest, const char* src, size_t n)
{if (dest == NULL || src == NULL) //检查dest和src参数是否合法,如果任意一个为NULL则直接返回NULL。{return NULL;}char* result = dest;// 保存dest的地址值,后面返回时使用size_t i;for ( i = 0; i < n && src[i] != '\0'; i++) //使用for循环复制字符。{ // i < n判断是否已经复制n个字符dest[i] = src[i]; // src[i] != '\0' 判断当前源字符串字符是否结束判断是否已经复制n个字符}//复制源字符串当前字符到目标字符串// 添加'\0'填充 (如果源字符串的⻓度⼩于`num`,则拷⻉完源字符串之后,在⽬标的后边追加`0`,直到`num`个。)while (i < n) 如果for循环结束但i未达到n,使用while循环填充'\0'。{dest[i++] = '\0';//将目标字符串当前位置字符填充为'\0'} //dest[i++] = '\0'先dest[i]='\0',后i++return result;
}
输出:
5
helxxxxxxxxxxxxxx
hello
调试界面:
- 用指针实现
char* my_strncpy(char* dest, const char* src, size_t n)
{assert(dest);//利用断言需要使用头文件#include<assert.h>assert(src);char* destPtr = dest;//定义dest和src的指针变量destPtr和srcPtr,用于遍历字符串。const char* srcPtr = src;while (n-- > 0) //使用while循环遍历n个字符{if (*srcPtr != '\0') //检查当前源字符串srcPtr指向的字符是否为'\0'结束符{*destPtr++ = *srcPtr++;//如果不是结束符,就将源字符串当前字符复制到目标字符串,} //并同时将两个指针前移到下一个字符。else //如果是结束符,进入else块{*destPtr++ = '\0';//将目标字符串当前字符设置为结束符'\0'} //然后destPtr再++}return dest; //返回目标字符串首地址。
}
输出:

*destPtr++ = *srcPtr++先进行一次赋值(*dest = *src),然后并使指针后移(dest=dest+1,src=src+1)
*destPtr++ = ‘\0’将目标字符串当前字符设置为结束符'\0',然后destPtr再++
🌠strncat 函数的使⽤
strncat函数用于连接两个字符串,将源字符串src连接到目标字符串dest的结尾,最多连接n个字符。
strncat函数的原型:
char *strncat(char *dest, const char *src, size_t n);dest:目标字符串,其内容将在其后追加源字符串内容。src:源字符串,其内容将被追加到目标字符串结尾。 n:要从源字符串中追加到目标字符串中的最大字符数。
- 返回值:
函数返回目标字符串dest的指针。
例子:
#include <string.h>
int main()
{char dest[100] = "Hello";char src[] = " World";strncat(dest, src, 6);printf("%s\n", dest);
}
输出:
输出 Hello World
🌉strncat 模拟实现
- 主函数
int main()
{char str1[100] = "hello";char str2[100] = " world";my_strncat(str1, str2, 5);printf("%s\n", str1);return 0;}
- 用数组模拟实现
char* my_strncat(char* dst, const char* src, size_t n)
{char* tmp = dst;while (*dst)//使用while循环遍历dst字符串。{dst++;//找到字符串结束位置'\0'。}int i;for (i = 0; src[i] && i < n; i++)// i < n 判断是否超过最大复制长度n{ //src[i] 判断源字符串是否结束dst[i] = src[i];}dst[i] = 0;//在目标字符串末尾添加字符串结束标记'\0'。return tmp;
}
输出:
hello worl

- 用指针实现
char* my_strncat(char* dest, const char* src, size_t n)
{//参数检查if (dest == NULL || src == NULL){return NULL;}char* ptr = dest;//找到目标字符串结尾while (*dest != '\0'){dest++;}while (n-- > 0 && *src != '\0'){*dest++ = *src++;}*dest = '\0';return ptr;//添加字符串结束符
}
输出:

首先,
n--表示先使用n的值来进行比较是否>0,因为&&是逻辑与运算符,*src != ‘\0’ 表示判断指针src所指向的字符是否为字符串的结束符\0,这两个条件验证真假后,最后n的值才减1。
🌠strncmp函数的使⽤
strncmp用于比较两个字符串的前n个字符。(比较的不是字符串的长度无关,只与对应位置的字符内容有关。)
strncmp函数原型:
int strncmp(const char *str1, const char *str2, size_t n);
str1 - 要比较的第一个字符串的指针
str2 - 要比较的第二个字符串的指针
n - 将被比较的最大字符数
返回值:
- 如果
str1小于str2,返回值小于0 - 如果
str1大于str2,返回值大于0 - 如果
str1等于str2,返回值等于0
注意点:
-
如果
n的值大于两个字符串中任意一个字符串的长度,比较将会超出字符串的范围,可能导致内存访问错误。因此,在使用strncmp函数时,需要确保n的值不会超过任意一个字符串的长度。 -
strncmp函数返回的结果是一个整数,可以通过结果的正负值来判断两个字符串的大小关系。 -
比较规则与
strcmp函数一致,按ASCII码顺序比较每个字符。
使用示例:
int main()
{char str1[] = "hello";//注意字符串结尾后面还有\0char str2[] = "hello world";int result1 = strncmp(str1, str2, 5);// 只比较前5个字符,结果为0,表示相等printf("%d\n", result1);int result2 = strncmp(str1, str2, 6);// 比较前6个字符,结果为负数,表示str1小于str2printf("%d\n", result2);}
输出:

🌉strncmp模拟实现
int my_strncmp(const char* s1, const char* s2, size_t n)
{int i = 0;//这是一个 for 循环,用于迭代比较两个字符串中的字符。for (; i < n && s1[i] != '\0' && s2[i] != '\0'; i++){if (s1[i] != s2[i]){return s1[i] - s2[i];//如果当前位置的两个字符不相等,返回它们的差值。}}if (i <= n){return s1[i] - s2[i];//如果 i 小于等于 n,但是循环结束了(即至少一个字符串已经达到结束符 ‘\0’),则返回当前位置字符的差值。}return 0;
}
int main()
{char s1[] = "hello";char s2[] = "helloworld";int result = my_strncmp(s1, s2, 5);printf("result = %d\n", result);return 0;
}
运行:
监视:
图解:
🌠strerror
| 错误码 | 错误描述 |
|---|---|
| 0 | No error |
| 1 | Operation not permitted |
| 2 | No such file or directory |
| 3 | No such process |
| 4 | Interrupted function call |
| 5 | Input/output error |
| 6 | No such device or address |
| 7 | Arg list too long |
| 8 | Exec format error |
| 9 | Bad file descriptor |
strerror函数用于将错误码转换为对应的错误信息字符串。
函数原型如下:
char *strerror(int errnum);
errnum: 错误码号,通常是系统调用或库函数返回的错误号。
strerror函数接受一个整型参数errnum,表示错误码。它会返回一个指向错误信息字符串的指针。
注意点:
- 在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在
errno.h这个头⽂件中#include <errno.h> - C语⾔程序启动的时候就会使⽤⼀个全⾯的变量
errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表⽰没有错误。 - 当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会讲对应
的错误码,存放在errno中 - 以每⼀个错误码都是有对应的错误信息的
- strerror函数返回的是一个静态字符串指针,不需要手动释放内存。
举栗子:
#include <errno.h>
#include <string.h>
#include <stdio.h>
int main()
{int i = 0;for (i = 0; i < 10; i++){printf("%d: %s\n",i, strerror(i));}return 0;
}
输出:

如何使用strerror函数打印打开文件失败的错误信息:
int main()
{FILE* pFile;pFile = fopen("unexist.txt", "r");//使用fopen函数打开文件"unexist.txt",以只读方式打开。if (pFile == NULL)//判断打开结果pFile是否为NULL,NULL表示打开失败。printf("Error opening file unexist.ent: %s\n", strerror(errno));elseprintf("打开文件成功\n");return 0;
}
输出:

分析:
Error opening file unexist.ent: No such file or directory说明打开文件"unexist.txt"失败,失败原因是文件不存在(ENOENT错误码)。
如果加上"unexist.txt"该文件,就会显示打开成功!
🌉 perror
perror函数用于打印错误信息。它的功能与strerror函数类似,但打印方式不同。
perror函数原型:
void perror(const char *s);
s: 可选的错误前缀信息。
简意:
perror函数直接打印到标准错误输出,打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。(此代码结果为下面代码运行)
详解:
将errno设置的错误号转换为错误描述字符串,然后打印到标准错误输出stderr上。如果s不为空,则在错误描述前加上s后跟 冒号 ":"。(stderr是预定义的一个文件输出流,它用于输出错误和诊断信息。stderr默认连接到控制台,输出到屏幕。所以向stderr输出的信息直接打印在屏幕上。)
使用perror函数需要包含错误头文件errno.h。
栗子:
int main()
{FILE* pFile;pFile = fopen("unexist.txt", "r");if (pFile == NULL)//printf("Error opening file unexist.ent: %s\n", strerror(errno));perror("Error opening file:");elseprintf("打开文件成功\n");return 0;
}
运行结果:

🚩总结
这次阿森和你一起学习6个C语言中常用的基本字符操作函数,但阿森会慢慢和你一起学习。感谢你的收看,如果文章有错误,可以指出,我不胜感激,让我们一起学习交流,如果文章可以给你一个小小帮助,可以给博主点一个小小的赞😘

相关文章:
【C语言】超详解strncpystrncatstrncmpstrerrorperror的使⽤和模拟实现
🌈write in front :🔍个人主页 : 啊森要自信的主页 ✏️真正相信奇迹的家伙,本身和奇迹一样了不起啊! 欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助&am…...
【Spring Boot 】Spring Boot 常用配置总结
文章目录 前言1.多环境配置application.propertiesapplication.yaml 2.常用配置3.配置读取4.自定义配置 前言 在涉及项目开发时,通常我们会灵活地把一些配置项集中在一起,如果你的项目不是很大的情况下,那么通过配置文件集中不失为一个很好的…...
Day60力扣打卡
打卡记录 1682分了记录下,希望下回能突破1700捏🤣🤣。作为一个菜鸟😨,知道自己不太行😭👊,从以前的周赛稳定1题到稳定2题🥺,到现在的时有时无的3题ǹ…...
Axure的动态图使用以及说明
认识Axure动态图 Axure动态图是Axure中的一种功能,它允许用户在原型中添加动画效果和交互动作,使原型更加生动和具有真实的用户体验。用户可以通过添加动态图来展示页面过渡、按钮点击、下拉菜单等交互操作的效果。 这是:就是我们今天要叫的…...
力扣 | 437. 路径总和 III
437. 路径总和 III mport java.util.ArrayList; import java.util.List;/*** int的取值范围:* -2^31 ~ 2^31-1* <p>* -2147483648 ~ 2147483647(约等于10的9次方)* <p>* long long的取值范围:* -2^63 ~ (2^63-1&…...
如何部署自己的服务渲染页面为Pdf文档
前言 相信大家都觉得官方发布的文档生成模块https://docs.mendix.com/appstore/modules/document-generation/很有用,它能把Mendix页面像素级导出到Pdf文件中,这对于归档等业务非常有价值。但部署依赖公有云提供的渲染服务,而中国本土用户对…...
常用的调试方法(段错误产生原因)
C 语言中常用的调试技巧和 demo C语言中常用的调试方法 打印调试信息 GDB 调试器 编写单元测试 段错误产生原因 初学时两种常用的段错误调试方法 C 语言中常用的调试技巧和 demo 当程序员进行调试时,他们通常会使用一些调试语句或技巧来帮助他们理解代码的执行过程…...
[云原生] Docker 入门指南:镜像、容器、卷和网络解析
Docker 是一种流行的容器化平台,它以其强大的功能和易用性在软件开发和部署领域广受欢迎。本文将带领您逐步探索 Docker 中的四个核心概念:镜像、容器、卷和网络。通过了解这些概念的是什么、为什么以及如何使用,您将能够更好地理解和利用 Do…...
机器学习-聚类问题
前言 聚类算法又叫做”无监督分类“,目标是通过对无标记训练样本来揭示数据的内在性质及 规律,为进一步的数据分析提供基础。 Kmeans 作为聚类算法的典型代表,Kmeans可以说是最简单的聚类算法,没有之一,那她是怎么完…...
leetcode9.回文数java解法
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。 回文数是指正序(从左向右)和倒序(从右向左&…...
图论专栏一《图的基础知识》
图论(Graph Theory)是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些实体之间的某种特定关系,用点代表实体,用连接两点的线表示两个实体间具有的…...
得帆云为玉柴打造CRM售后服务管理系统,实现服务全过程管理|基于得帆云低代码的CRM案例系列
广西玉柴机器股份有限公司 广西玉柴机器股份有限公司始建于1992年,是国内行业首家赴境外上市的中外合资企业,产品远销亚欧美非等180多个国家和地区。公司总部设在广西玉林市,下辖11家子公司,生产基地布局广西、江苏、安徽、山东等…...
智能优化算法应用:基于蝠鲼觅食算法3D无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于蝠鲼觅食算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于蝠鲼觅食算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝠鲼觅食算法4.实验参数设定5.算法结果6.…...
vue2 以及 vue3 自定义组件使用 v-model使用默认值以及自定义事件
vue2 以及 vue3 自定义组件使用 v-model使用默认值以及自定义事件 1. vue2 自定义组件的 v-model vue2官网,自定义组件官方解释:一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件上代码代码中使用了 element-ui 子组件 使用默…...
《PCL多线程加速处理》-滤波-统计滤波
《PCL多线程加速处理》-滤波-统计滤波 一、效果展示二、实现方式三、代码一、效果展示 提升速度随着点云越多效果越明显 二、实现方式 1、原始的统计滤波实现方式 #include <pcl/filters/statistical_outlier_removal.h>pcl::PointCloud<pcl::PointXYZ...
插入排序——直接插入排序和希尔排序(C语言实现)
文章目录 前言直接插入排序基本思想特性总结代码实现 希尔排序算法思想特性总结代码实现 前言 本博客插入排序动图和希尔排序视频参考大佬java技术爱好者,如有侵权,请联系删除。 直接插入排序 基本思想 直接插入排序是一种简单的插入排序法ÿ…...
【Linux系统化学习】进程地址空间 | 虚拟地址和物理地址的关系
个人主页点击直达:小白不是程序媛 Linux专栏:Linux系统化学习 代码仓库:Gitee 目录 虚拟地址和物理地址 页表 进程地址空间 进程地址空间存在的意义 虚拟地址和物理地址 我们在学习C/C的时候肯定都见过下面这张有关于内存分布的图片&a…...
Navicat 技术指引 | 适用于 GaussDB 分布式的模型功能
Navicat Premium(16.3.3 Windows 版或以上)正式支持 GaussDB 分布式数据库。GaussDB 分布式模式更适合对系统可用性和数据处理能力要求较高的场景。Navicat 工具不仅提供可视化数据查看和编辑功能,还提供强大的高阶功能(如模型、结…...
四十五、Redis主从
目录 1、数据同步原理 (1)全量同步 (2)增量同步 (3)优化Redis主从集群 (4)什么时候执行全量同步 (5)什么时候执行增量同步 2、流程 1、数据同步原理 &…...
Spring源码学习一
IOC容器概述 ApplicationContext接口相当于负责bean的初始化、配置和组装的IoC容器. Spring为ApplicationContext提供了一些开箱即用的实现, 独立的应用可以使用 ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext,web应用在web.xml配置监 听&am…...
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…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
UE5 音效系统
一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类,将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix,将上述三个类翻入其中,通过它管理每个音乐…...
基于stm32F10x 系列微控制器的智能电子琴(附完整项目源码、详细接线及讲解视频)
注:文章末尾网盘链接中自取成品使用演示视频、项目源码、项目文档 所用硬件:STM32F103C8T6、无源蜂鸣器、44矩阵键盘、flash存储模块、OLED显示屏、RGB三色灯、面包板、杜邦线、usb转ttl串口 stm32f103c8t6 面包板 …...








