C:字符串函数(续)-学习笔记


穗
一些闲话:
最近玩了这款饿殍-明末千里行,不知大家是否有听过这款游戏,颇有感触!!!
游戏中最让我难以忘怀的便是饿殍穗线的故事,生在如今时代的我之前无法理解杜甫在目睹人间悲剧时的心情,但现在我似乎有些能够共情了。在游戏中我以第三人称视角目睹了一个美好家庭的支离破碎的过程,那种痛苦难以言表。天灾人祸,饿殍遍野,有人在笑,有人在哭,富人更富,穷人死亡。
前言:
本篇文章将延续上一篇继续介绍字符串函数,希望能够对大家有所帮助!
话不多说,直接上正文
上一篇文章我们将字符串函数分为四类,并介绍了strlen函数

本篇文章小编将会带着大家了解后面三类字符串函数
1、 strcpy与strncpy
1.1 strcpy的使用和模拟
1.1.1 strcpy的使用

strcpy -- string copy 字符串拷贝
这是什么意思呢?
char ch1[] = "Hello,world"; char ch2[20];比如说你有一个字符串ch1,想要将ch1中的内容拷贝到ch2中,这时候我们就可以使用strcpy函数了
那么这个函数该怎么使用呢?
函数原型:
char * strcpy ( char * destination, const char * source );
我们来看一下cplusplus上是怎么说明的

也就是说destination是目标空间,sourse是源头

我们将源头里的内容拷贝到目的地中,在结合我们上面举的例子,我们想将ch1中的内容拷贝到ch2中,那么ch1便是源头,ch2便是目标空间。
代码实现:
#include <stdio.h>
#include <string.h>
int main()
{char ch1[] = "Hello,world";char ch2[20];strcpy(ch2, ch1);printf("%s\n", ch2);return 0;
}
结果展示:

这便是strcpy的作用,当我们学会了strcpy的使用,我们还需要知道为什么,知其然知其所以然

我们验证一下有没有将\0一同拷贝
char ch1[] = "Hello";char ch2[20] = "*************";//为了方便观察是否拷贝了\0strcpy(ch2, ch1);

从调试过程中我们可以发现 \0 的确是拷贝过来了。
既然strcpy会将源头内容中的\0拷贝过来,那么如果源头不包含\0的话,会有什么结果呢?
char ch1[] = { 'a','b','c'};
char ch2[20] = "*************";//为了方便观察是否拷贝了\0
strcpy(ch2, ch1);

这里为什么会出现这样的错误呢?
就是因为源头内容中不存在\0。没有\0
strcpy拷贝就停不下来,会一直拷贝,直到越界报错。
因此 strcpy函数的使用需要注意几点
- 源字符串必须以 '\0' 结束。
- 目标空间必须足够大,以确保能存放源字符串
- 目标空间必须可修改
1.1.2 strcpy的模拟实现
当学会strcpy怎么使用后,我们也可以尝试自己写一个函数来模拟一下strcpy
#include <stdio.h>
#include <string.h>
void my_strcpy(char* ch2, char* ch1)
{while (*ch1 != '\0'){*ch2 = *ch1;*ch2++;*ch1++;}*ch2 = *ch1;//如果*ch1 = '\0',ch2 = '\0'
}
int main()
{char ch1[] = "hello";char ch2[20];my_strcpy(ch2, ch1);printf("%s\n", ch2);return 0;
}

当ch1不等于 '\0' 的时候,就继续向后寻找,且令ch2 = ch1;
当ch1等于 '\0' 的时候,则不再向后寻找,令ch2 = ch1;
void my_strcpy(char* ch2, char* ch1)
{while (*ch1 != '\0'){*ch2 = *ch1;*ch2++;*ch1++;}*ch2 = *ch1;//如果*ch1 = '\0',ch2 = '\0'
}
上面那个模拟实现还可以进行一些优化,我们可以再进行简化一下
比如说*ch2++和*ch1++可以与上面的合并一下
*ch2++ = *ch1++;
后置++是用完之后再++,所以和前面的表示是一样的。
前面我们将*ch1 分为是否等于 '\0',这里也可以合并一下
void my_strcpy(char* ch2, char* ch1)
{while (*ch2++ = *ch1++ ){;}
}
分析一下:

循环结束是因为\0 的ASCLL值为0,0为假,循环终止。
这样写的好处是既可以赋值,赋完的值还可以用来判断。
还有一个问题,我们使用strcpy函数主要是为了将源头内容拷贝到目标空间中,因此,我们不希望源头被改动,因此,可以使用const修饰一下源头
void my_strcpy(char* ch2, const char* ch1)
这样的话我们就不能够在my_strcpy函数中修改ch1中的内容了, 使得程序更加稳定。
关于指针我们最担心的是什么?我们会担心它是不是空指针,因此可以在解引用之前使用assert断言一下。
assert(ch2 && ch1 );//只要有一个是空指针就会报错
注意,assert使用需要添加头文件<assert.h>
最终版本:
#include <stdio.h>
#include <string.h>
#include <assert.h>
void my_strcpy(char* ch2, const char* ch1)
{assert(ch2 && ch1 );//只要有一个是空指针就会报错while (*ch2++ = *ch1++ ){;}
}
int main()
{char ch1[] = "hello";char ch2[20];char* ret = my_strcpy(ch2,ch1);printf("%s\n", ret);return 0;
}
1.2 strncpy的使用
这个函数和strcpy是不是很相似,它们不仅名字相似,用法也及其相似


他们之间就相差了一个变量,strncpy比strcpy多了一个变量num,那么num这个变量的作用是什么呢?

num的作用
其实它们之间唯一的区别就是strncpy是长度受限制的字符串函数,而strcpy是长度不受限制的字符串函数,也就是说你源头字符串长度不论多少,都会全部给你 拷贝到目标空间中;而strncpy则会通过num的值来拷贝源头字符串长度到目标空间。
//我们要拷贝arr1中的前五个元素
char arr1[] = "hello world";
char arr2[30] = { 0 };
strncpy(arr2,arr1,5);
printf("%s ", arr2);

最终打印出来的便是我们想要的前五个字符。
有没有觉得strncpy函数比strcpy函数要灵活一些,使用strncpy函数我们可以根据自己的需求来决定拷贝多少字符,但是使用strcpy函数却只能拷贝全部的字符。
strncpy加上了一个长度的限制使得拷贝变的更加灵活。
char arr1[] = "he"; char arr2[30] = "xxxxxxxxx"; strncpy(arr2,arr1,5); printf("%s ", arr2);如果我们源头字符串不足所要拷贝的长度,会怎样呢?
从上图中我们可以看到,如果不满足条件,后面会自动补充上\0。
2、strcat与strncat
2.1 strcat的使用与模拟
2.1.1 strcat的使用

strcat的作用是实现字符串的链接
那么什么是字符串的链接呢?
比如说有一个字符数组arr,内容是"hello",想要在后面追加world,这时候就需要使用strcat函数了
char arr[20] = "hello "; strcat(arr, "world");这样我们就可以将world链接到arr中,打印arr,可以看到此时arr的内容变成了 "hello world"
函数原型:
char * strcat ( char * destination, const char * source );
cplusplus中对strcat的解释:

这里有两个问题,第一个问题是strcat函数的追加是不是从我们字符串遇到的第一个\0开始追加?

第二个问题是 上图中的 '\0' 是原来的函数把 "world" 字符串中的' \0 '追加到arr中的吗?
我们来验证一下
char arr[20] = "hello\0xxxxxxx ";
strcat(arr, "world")

上图就可以解决我们的两个问题了,strcat函数的追加是从我们字符串遇到的第一个\0开始追加
"world" 字符串中的' \0 '也会追加到arr中
因此,我们可以整理一下strcat函数的追加方式:
1.找到目标空间中的第一个'\0';
2.然后从\0的位置开始追加源头字符串;
3.源头字符串的内容包括\0都会追加到目标空间。
2.1.2 strcat的模拟实现
学会了strcat函数的使用,接下来我们尝试模拟一下;
//dest指目标空间也就是arr;src指源头,也就是所要追加的字符串首字符的地址
char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest && src);//1.找目标空间中的\0while (*dest != '\0')dest++;//2.拷贝数据while (*dest++ = *src++){;}return ret;
}
int main()
{char arr[20] = "hello ";my_strcat(arr, "world");printf("%s ", arr);return 0;
}
提出一个问题,我们能不能用上面自己模拟的my_strcat来实现自己给自己追加的操作?

因此,使用上面自己定义的函数来实现自己给自己追加最终会出现死循环问题。
如果我们使用库里面的strcat函数呢?

当前程序可以,但是呢,没法保证所有程序都可以成功运行,一般我们不会使用这个函数给自己追加。 一般自己自己追加都使用 strncat 函数
2.2 strncat的使用
strncat函数与strcat函数的用法也是一样的,都是实现字符串的链接,不过前者会加上链接字符的长度限制。

strncpy用法展示:
char arr[30] = "hello ";
strncat(arr,"liangjing",5 );
printf("%s ", arr);

如果我们要追加的字符串少于所规定的长度呢?
char arr[30] = "hello\0xxxxxx ";
strncat(arr,"lj",5);
printf("%s ", arr);
我们可以发现strncat函数不会和strncpy函数一样,不满足会给你补\0, strncat函数只会把最多追加到目标空间。
3、strcmp与strncmp
3.1 strcmp的使用与模拟
3.1.1 strcmp的使用

strcmp -- string compare -字符串的比较
strcmp函数的作用是比较两个字符串的大小
对应位置上的字符进行比较,按照ASCII值的大小,注意比较的不是字符串的长度。
比如说:
函数原型:
int strcmp ( const char * str1, const char * str2 );我们来看一看这个函数的参数
const char * str1是一个字符指针,const char * str2 也是一个字符指针,该函数将两个指针指向的字符串进行比较,比较后,在通过返回值来告诉我们谁大谁小
这是什么意思呢?如果说str1指向的字符串比str2指向的字符串大,则返回一个大于0的数字,如果相等,返回0,如果str1指向的字符串比str2指向的字符串小,则返回一个小于0的数字。
char arr1[ ] = "abcdef ";
char arr2[ ] = "abc";
int ret = strcmp(arr1, arr2);
printf("%d",ret);
我们来看一下返回值大小:

返回1,也就是说明字符串arr1大于字符串2
我们也可以将这个代码换一种表示,或许会更加直观
int main()
{char arr1[ ] = "abcdef ";char arr2[ ] = "abc";int ret = strcmp(arr1, arr2);if (ret > 0)printf(">\n");else if (ret < 0)printf("<\n");elseprintf("=\0");return 0;
}
这样使用比较符号可以更加直观。
注意:strcmp函数是通过比较两个字符串对应位置ASCII值的大小来判断两个字符串的大小,而不是通过字符串长度。
3.1.1 strcmp的模拟实现
学会了使用strcmp,我们可以尝试自己来模拟实现该函数
int my_strcmp(const char* str1, const char* str2)
{while (*str1 == *str2){if (*str1 == '\0')return 0;str1++;str2++;}if (*str1 > *str2)return 1;elsereturn -1;
}
int main()
{char arr1[ ] = "abcdef ";char arr2[ ] = "abc";int ret = my_strcmp(arr1, arr2);if (ret > 0)printf(">\n");else if (ret < 0)printf("<\n");elseprintf("=\0");return 0;
}
3.2 strncmp的使用

与上类似,直接展示用法:
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main()
{char arr1[30] = "abcdef ";char arr2[30] = "abcmne";int ret = strcmp(arr1,arr2,3);if (ret > 0)printf(">\n");else if (ret < 0)printf("<\n");elseprintf("=\0");return 0;
}
这里的3是指只比较字符串arr1,arr2中前三个字符
结语:
本篇文章主要是介绍了strcpy,strcat,strcmp以及与它们极其相似的strncpy,strncat,strncmp函数,下篇文章将会结束字符串函数模块。

相关文章:
C:字符串函数(续)-学习笔记
穗 一些闲话: 最近玩了这款饿殍-明末千里行,不知大家是否有听过这款游戏,颇有感触!!! 游戏中最让我难以忘怀的便是饿殍穗线的故事,生在如今时代的我之前无法理解杜甫在目睹人间悲剧时的心情&…...
Depth靶机详解
靶机下载地址 https://www.vulnhub.com/entry/depth-1,213/ 主机发现 arp-scan -l 端口扫描 nmap -sV -A -T4 192.168.229.156 端口利用 http://192.168.229.156:8080/ 目录扫描 dirb "http://192.168.229.156:8080" dirsearch -u "http://192.168.229.15…...
go get -u @latest没有更新依赖模块
使用 go get -u gitee.com/qingfeng-169/hello-blatest 时,如果没有进行更新,可能有以下几种原因: 1. 没有发布稳定版本 (vX.X.X) latest 表示获取该模块最新的稳定版本(即带有 vX.X.X 形式的版本号),而不…...
介绍一些免费 的 html 5模版网站 和配色 网站
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、H5 网站介绍网站 二、配色网站个人推荐 前言 提示:以下是本篇文章正文内容,下面案例可供参考 一、H5 网站介绍 以下是一些提供免费…...
【C++】入门基础(下)
Hi!很高兴见到你~ 目录 7、引用 7.3 引用的使用(实例) 7.4 const引用 【第一分点】 【第二分点1】 【第二分点2】 7.5 指针和引用的关系(面试点) 8、inline 9、nullptr Relaxing Time! ———…...
Spring Boot 集成 MongoDB - 入门指南
引言 随着NoSQL数据库的流行,MongoDB 成为了许多现代Web应用程序的首选数据库之一。它提供了高性能、高可用性和易于扩展的能力。Spring Boot 框架以其开箱即用的理念简化了Java应用程序的开发过程。本文将指导您如何在Spring Boot项目中集成MongoDB,以…...
基于云计算的虚拟电厂负荷预测
基于云计算的虚拟电厂负荷预测 随着电网规模的扩大及新能源的不断应用,并网电网的安全性和经济性备受关注。 电网调度不再是单一或局部控制,而是采用智能网络集成方式调度 。 智能电网应具有以下特点:坚强自愈,可以抵御外来干扰甚…...
Android应用性能优化
Android手机由于其本身的后台机制和硬件特点,性能上一直被诟病,所以软件开发者对软件本身的性能优化就显得尤为重要;本文将对Android开发过程中性能优化的各个方面做一个回顾与总结。 Cache优化 ListView缓存: ListView中有一个回…...
fiddler抓包01:工具介绍
课程大纲 fiddler是一款常见的抓包工具,可以对web端和移动端的接口请求进行抓包(截获)、分析、编辑、模拟等,还可以导出jmeter、Loadrunner测试脚本。 1、原理 fiddler作为代理服务器,拦截请求和服务器响应。 2、使用…...
Spring Boot母婴商城:打造一站式购物体验
1 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大,随着当前时代的信息化,科学化发展,让社会各行业领域都争相使用新的信息技术,对行业内的各种相关数据进行科学化,规范化管理。这样的大环境让那些止步不前&#…...
【面试八股总结】GC垃圾回收机制
垃圾回收策略(Garbage Collection,GC)用于回收不再使用的内存,避免系统的内存被占满。Go1.3之前采用标记清除法, Go1.3之后采用三色标记法,Go1.8采用三色标记法混合写屏障。 前置概念: 1&#x…...
arcgisPro修改要素XY容差
1、在arcgisPro中XY容差的默认值为1个毫米,及0.001米。为了更精细的数据,需要提高这个精度,如何提高呢? 2、如果直接在数据库下新建要素类,容差只能调至0.0002米。所以,需要在数据库下新建要素数据集。 3…...
Java 21的Enhanced Deprecation的笔记
Java Core Libraries Enhanced Deprecation 废弃API,一般可以理解为不推荐开发者在项目中使用的API,当前为了保持兼容,在JDK中保留,未来可能会删除。 作为开发者,使用工具jdeprscan可以方便的查找现有代码中存在的一些…...
Ubuntu下Git使用教程:从入门到实践
引言 在软件开发和版本控制领域,Git无疑是最为流行的工具之一。它不仅能够帮助我们高效地管理代码,还能促进团队协作,确保项目的持续集成与交付。对于使用Ubuntu操作系统的开发者而言,掌握Git的使用技巧尤为重要。本文将带您一步…...
【开放词汇检测】基于MMDetection的MM-Grounding-DINO实战
文章目录 摘要安装基础环境新建虚拟环境安装pytorch安装openmim、mmengine、mmcv安装 MMDetection验证安装配置OV-DINO环境 MMDetection的MM-Grounding-DINO详细介绍测试结果Zero-Shot COCO 结果与模型Zero-Shot LVIS ResultsZero-Shot ODinW(野生环境下的目标检测&…...
PLC-Recorder 对西门子传动的采集方法
目录 一、增加西门子传动的通道 二、变量配置 2.1 语法格式 a:装置号 b:参数号 c:参数下标 2.2 配置及连接测试情况 三、正式采集 四、小结 PLC-Recorder V3.4.0版本增加了西门子传动参数采集的功能(增加了传动的设备类型&a…...
【网络通信基础与实践第三讲】传输层协议概述包括UDP协议和TCP协议
一、进程间的通信 通信的两端应当是两个主机中的应用进程,也就是说,端到端的通信是应用进程之间的通信 运输层有一个很重要的功能就是复用和分用,复用是指在发送方不同的应用进程都可以使用同一个运输层协议传送数据,分用是指接…...
centos更改静态ip
点击网络和internet设置 点击更改适配器 、点击属性...
YOLOv5/v8 + 双目相机测距
yolov5/v8双目相机测距的代码,需要相机标定 可以训练自己的模型并检测测距,都是python代码 已多次实验,代码无报错。 非常适合做类似的双目课题! 相机用的是汇博视捷的双目相机,具体型号见下图。 用的yolov5是6.1版本的…...
双三次插值及MATLAB实现
一、双三次插值的概念 双三次插值(Bicubic interpolation),又叫双立方插值。在数值分析这个数学分支中,双三次插值是二维空间中最常用的插值方法。在这种方法中,函数f在点 (x0 ,y0) 的值不仅考虑其直接邻接点对其的影响…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...
AT模式下的全局锁冲突如何解决?
一、全局锁冲突解决方案 1. 业务层重试机制(推荐方案) Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减(自动加全…...
python3GUI--基于PyQt5+DeepSort+YOLOv8智能人员入侵检测系统(详细图文介绍)
文章目录 一.前言二.技术介绍1.PyQt52.DeepSort3.卡尔曼滤波4.YOLOv85.SQLite36.多线程7.入侵人员检测8.ROI区域 三.核心功能1.登录注册1.登录2.注册 2.主界面1.主界面简介2.数据输入3.参数配置4.告警配置5.操作控制台6.核心内容显示区域7.检…...
MySQL用户远程访问权限设置
mysql相关指令 一. MySQL给用户添加远程访问权限1. 创建或者修改用户权限方法一:创建用户并授予远程访问权限方法二:修改现有用户的访问限制方法三:授予特定数据库的特定权限 2. 修改 MySQL 配置文件3. 安全最佳实践4. 测试远程连接5. 撤销权…...
NoSQL——Redis配置与优化
目录 关系型&非关系型数据库 一、核心原理对比 二、核心特性对比 三、关键区别剖析 四、典型产品示例 总结 Redis Redis核心原理 核心特性 技术意义 配置文件解析 1. 基础配置 2. 持久化配置 3. 内存管理 4. 高可用配置 5. 性能调优 6.…...
Ubantu-Docker配置最新镜像源250605
尝试其他镜像加速器 阿里云镜像加速器:登录阿里云,进入容器镜像服务获取专属加速器地址。毫秒镜像:https://docker.1ms.run。DockerHub镜像加速器:https://docker.xuanyuan.me。Docker Hub 镜像加速服务:https://dock…...





