【C语言】字符串函数strcpystrcatstrcmpstrstr的使⽤和模拟实现

  🌈write in front :

🔍个人主页 : @啊森要自信的主页

✏️真正相信奇迹的家伙,本身和奇迹一样了不起啊!

欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助,如有错误,可以指出,让我们一起探讨学习交流,一起加油鸭。 请添加图片描述

文章目录

  • 📝前言
  • 🌠 库函数strcpy
    • 🌉strcpy的模拟实现
  • 🌠库函数strcat
    • 🌉strcat的模拟实现
  • 🌠strcmp 的使⽤
    • 🌉strcmp 模拟实现
  • 🌠 strstr 的使⽤
    • 🌉strstr 的模拟实现
  • 🚩总结


📝前言

记上节,我们学了字符串strlen的使用和三种模拟实现方法,本小节,阿森继续和你一起学习4个字符串函数:strcpystrcatstrcmpstrstr的使用和他的模拟实现方法,学习这些库函数,可以更好的方便操作字符和字符串,文章干货满满,接下来我们就学习一下这些函数吧!


🌠 库函数strcpy

strcpy函数是将源字符串拷贝到目标字符串中,覆盖目标字符串原有内容。

char *strcpy(char *dest, const char *src);
dest:目标字符串,用于保存拷贝结果。
src:源字符串,将其内容拷贝到dest中。
返回值:返回目标字符串dest的指针。

注意点:

  • strcpy函数会将src字符串中的字符一个一个地复制到dest字符串中,直到遇到字符串结束标志'\0'为止。

  • src字符串必须以'\0'结束。

  • 会将源字符串中的 '\0' 拷⻉到⽬标空间。

  • dest字符串要有足够的空间,不然会导致缓冲区溢出。
    在这里插入图片描述

  • 目标空间必须是可修改的
    在这里插入图片描述

代码:

int main()
{char arr1[20] = "xxxxxxxxx";char arr2[] = {'a', 'b', 'c','\0'};strcpy(arr1, arr2);printf("%s\n", arr1);return 0;
}

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

🌉strcpy的模拟实现

  1. 方法一
void my_strcpy(char* dest, char* src)
{while (*src != '\0'){*dest = *src;dest++;src++;}*dest = *src;
}
int main()
{char arr1[20] = { 0 };char arr2[] = "abcdef";my_strcpy(arr1, arr2);printf("arr1 after copy: %s\n", arr1);return 0;
}

分析: 使用while循环,循环条件是源字符串src指针指向的字符不为'\0',每次循环体内,将src指向字符复制到dest指向位置,分别使destsrc指针后移,指向下一个字符位置,循环结束后,将字符串结束符'\0'也复制到dest指向位置

  1. 方法二
    第一种方法缺陷太多了,比如没有返回值,无法知道拷贝是否成功。
char* my_strcpy(char* dest, const char* src)
{assert(dest != NULL);assert(src != NULL);检查dest和src参数是否为NULL,NULL参数会导致访问异常。需要#include <assert.h>char* ret = dest;保存dest原始地址到ret变量,后面返回值使用。assert(dest && src);再次检查dest和src是否合法,防御性编程。while (*dest++ = *src++){;}return ret;
}

while (*dest++ = *src++)
先一次赋值destsrc当前字符(*dest = *src),然后并使指针后(dest=dest+1,src=src+1),while循环结束条件是当src字符串末尾'\0'字符被复制时结束,当src指向\0,此时\0赋值给*dest,符合while循环结束条件,跳出循环.

🌠库函数strcat

strcat函数用于将源字符串src追加到目标字符串dest的结尾。

char *strcat(char *dest, const char *src);
dest - 目标字符串,必须有足够的空间存储追加后的结果字符串。
src - 源字符串。
返回值: 返回目标字符串dest的地址。

strcat首先找到dest字符串的结尾,即'\0'字符的位置。从dest字符串结尾开始,将src字符串一个字符一个字符地复制过来。将src字符串的结束'\0'字符也复制到dest后面。最后返回dest地址。

关键点:

  • 源字符串src必须以 '\0' 结束。
  • ⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。
  • dest必须有足够的空间存储追加后的结果字符串。
  • ⽬标空间必须可修改。
  • 字符串⾃⼰可不可以给⾃⼰追加?
    使用:
int main()
{char str1[20] = "Hello ";char str2[20] = "World";char str3[40];/* 复制str1到str3 */strcpy(str3, str1);/* 将str2追加到str3结尾 */strcat(str3, str2);printf("str3 = %s\n", str3);return 0;
}

输出:

str3 = Hello World
在这里插入图片描述

🌉strcat的模拟实现

  1. strcat的模拟实现一
char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest && src);检查参数是否合法。//1. 找到目标空间的\0使用while循环找到dest字符串的结束'\0'字符,dest指针指向字符串结束后的位置。while (*dest){dest++;}//2. 拷贝while (*dest++ = *src++){;}return ret;
}

while (*dest++ = *src++)先一次赋值destsrc当前字符(*dest = *src),然后并使指针后(dest=dest+1,src=src+1),先读取src的一个字符将字符赋给dest指向的位置,然后destsrc同时后移一个位置循环,当src指向\0,此时\0赋值给*dest,循环结束.

2.字符串⾃⼰可不可以给⾃⼰追加? 答案是:不能给自己追加

 char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest && src);//1. 找到目标空间的\0while (*dest){dest++;}//2. 拷贝while (*dest++ = *src++){;}return ret;
}int main()
{char arr1[20] = "hello";my_strcat(arr1, arr1);printf("%s\n", arr1);return 0;
}

运行代码图:
在这里插入图片描述
在这里插入图片描述

🌠strcmp 的使⽤

strcmp用于比较两个字符串是否相等,也就是比较字符串大小的函数。
函数原型:

int strcmp(const char *str1, const char *str2);
str1和str2是要比较的两个字符串指针。

strcmp比较字符串的大小,不是按字符串的长度进行比较,而是逐个字符地比较两个字符串对应的每个字符的ASCII码值。(比较使用的是无符号字符值的ASCII码顺序。)

  • 返回值:

    • 如果str1str2完全相等,返回0

    • 如果str1大于str2(按ASCII码顺序),返回一个大于0的数。

    • 如果str1小于str2,返回一个小于0的数。

  • strcmp()函数是C标准库string.h头文件中的函数。

  • 字符串比较结束条件是遇到字符串末尾'\0'字符或者第一个不匹配字符。

字符串"cat" 和 "dog" 的比较:
'c'的ASCII码是99, 'd'的ASCII码是100,所以"cat"小于"dog"字符串"hello" 和 "hello world" 的比较: 
前6个字符都相等,但第7个字符' '的ASCII码小于'\0',所以"hello"小于"hello world"

例子:

#include <string.h>int main()
{char str1[] = "ahbyb";char str2[] = "asyzx";  int result = strcmp(str1, str2);if(result == 0)printf("Strings are equal\n");else if(result > 0)  printf("str1 is greater than str2\n"); elseprintf("str1 is less than str2\n");return 0;
}

结果:

str1 is less than str2

在这里插入图片描述

🌉strcmp 模拟实现

int my_strcmp(const char* s1, const char* s2)
{while (*s1 == *s2){if (*s1 == '\0')return 0;s1++;s2++;}return *s1 - *s2;//if (*s1 > *s2)//	return 1;//else//	return -1;}

使用while循环逐个比较s1s2每个字符是否相等如果字符相等,继续循环比较下一个字符, 如果遇到字符串结束符’\0’,表示两个字符串完全匹配,直接返回0,如果在循环中找到不匹配的字符,使用*s1 - *s2返回两个字符的ASCII码差值

🌠 strstr 的使⽤

strstr用来查找一个字符串在另一个字符串中首次出现的位置。

strstr函数的原型:

char* strstr(const char* str1, const char* str2);
- str1: 主字符串,要在其中查找子字符串
- str2: 子字符串,要查找的字符串

strstr函数可以用来在一个字符串中查找另一个字符串首次出现的位置,如果str2不存在于str1中,则返回NULL;如果str2存在于str1中,则返回第一个匹配位置的指针。

strstr的比较原理是:

  1. str1字符串的起始位置开始,与str2字符串进行字符匹配比较。

  2. 如果匹配失败(当前字符不同),则str1指针后移一位,继续匹配。

  3. 如果匹配成功(到达str2字符串结束符'\0'),则匹配成功,返回str1指针地址。

  4. 如果遍历完str1仍未匹配成功,则返回NULL

例如:

char* p = strstr("hello world","world");
// p指向"world"子字符串在"hello world"中的位置

这里用一个图来解释strstr函数的工作原理:

        +----------------------+
str1 => | h e l l o   w o r l d| +----------------------+|V+-----------+
str2 => | w o r l d |+-----------+|V比较第一个字符'h'与'w',不匹配|V指针后移到下一个字符'e'|V比较'e'与'w',不匹配|V指针后移到下一个字符'l'|  V比较'l'与'w',不匹配|V指针后移,依次比较直到匹配成功|V当str1指针指向'w'时,与str2第一个字符'w'匹配|V开始匹配后续字符,全部匹配成功|V返回str1指针地址,指向子字符串在主字符串中的位置
int main()
{char arr1[] = "abcegtbaab";char arr2[] = "cegtba";char* ret = strstr(arr1, arr2);if (ret != NULL)printf("%s\n", ret);elseprintf("找不到\n");return 0;
}

结果:

cegtbaab

当然也可以用图展示:
在这里插入图片描述

strstrstr1起始位置开始,用str2str1进行字符匹配比较。如果不匹配就后移str1指针,匹配成功就返回str1当前位置指针,上图就是返回c的地址。通过这种逐个匹配的方式找到子字符串在主字符串中的第一个匹配位置。

🌉strstr 的模拟实现

char* my_strstr(const char* str1, const char* str2)
{const char* cur = str1;//用cur记录str1的位置const char* s1 = NULL;//使用assert检查str1和str2是否为非空指针。const char* s2 = NULL;assert(str1 && str2);if (*str2 == '\0')//检查str2是否为空字符串,如果为空直接返回str1。{return (char*)str1;}while (*cur)//使用cur指针遍历str1。{ //每次遍历:s1 = cur;//将cur赋值给s1,将str2赋值给s2,用于后续匹配s2 = str2;//当然,第几次失败后,重新回溯,重新开始匹配while (*s1 && *s2 && *s1 == *s2){s1++;//开始匹配s1和s2中的字符,同时递增s1和s2。s2++;}if (*s2 == '\0')如果s1和s2匹配到结尾('\0'),表示找到了子串,返回cur。{return (char*)cur;}cur++;匹配失败后,cur++继续下次匹配。}return NULL;遍历完str1没有找到匹配,返回NULL。
}

时间复杂度为O(MN),其中M和N分别为主串和子串的长度。
若老铁们有点蒙蒙的,可以结合下图来理解:
在这里插入图片描述


🚩总结

这次阿森和你一起学习4个C语言中常用的基本字符操作函数,当然这只是一部分,还有很多,但阿森会慢慢和你一起学习。感谢你的收看,如果文章有错误,可以指出,我不胜感激,让我们一起学习交流,如果文章可以给你一个小小帮助,可以给博主点一个小小的赞😘
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/211956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电源小白入门学习1——电源系统架构和相关指标

电源小白入门学习1——电源系统架构和相关指标 电源系统架构电源系统的指标及测量方法电源的效率电源的静态电流输出电压调整率纹波测量的注意事项动态负载测试 在开始本期内容之气&#xff0c;我先简单介绍一下我们电源小白学习系列内容&#xff1a;首先我是一个嵌入式小白&am…

在VSCode中运行Python脚本文件时如何传参

以下实验所处的操作系统环境说明&#xff1a; OS版本MacOSMonterey 12.1VSCodeOctober 2023 (version 1.84.2) 一、背景 在 VSCode 中写好 Python 脚本后&#xff0c;如果要运行起来&#xff0c;可以怎么做呢&#xff1f; 一般有以下几种方式&#xff1a; 1、直接在 VSCode…

sentinel整合nacos配置中心持久化

在网上找了很多的资料&#xff0c;发现sentinel整合nacos持久化的博文和视频大多数都只有改造限流部分的教程&#xff0c;并且都需要修改前端&#xff0c;略显麻烦&#xff0c;至于剩下的熔断、热点流控、授权的更是没有相关的改造教程&#xff0c;最后在知乎的看到一篇文章后让…

百科词条可以删除吗?如何删除自己的百度百科?

近日&#xff0c;小马识途营销顾问接到不少客户删除自己百科词条的咨询&#xff0c;有不少人自己并没有去建立百科词条&#xff0c;但是网上已经有了&#xff0c;有的信息不正确&#xff0c;甚至有的信息是负能量的&#xff0c;对当事人自己造成一定的困扰&#xff0c;所以寻求…

PbootCMS 前台RCE漏洞复现

0x01 产品简介 PbootCMS是全新内核且永久开源免费的PHP企业网站开发建设管理系统,是一套高效、简洁、 强悍的可免费商用的PHP CMS源码,能够满足各类企业网站开发建设的需要 0x02 漏洞概述 PbootCMS v<=3.1.6版本中存在模板注入,攻击者可构造特定的链接利用该漏洞,执行…

线程及实现方式

一、线程 线程是一个基本的CPU执行单元&#xff0c;也是程序执行流的最小单位。引入线程之后&#xff0c;不仅是进程之间可以并发&#xff0c;进程内的各线程之间也可以并发&#xff0c;从而进一步提升了系统的并发度&#xff0c;使得一个进程内也可以并发处理各种任务&#x…

【Hive】——安装部署

1 MetaData&#xff08;元数据&#xff09; 2 MetaStore &#xff08;元数据服务&#xff09; 3 MetaStore配置方式 3.1 内嵌模式 3.2 本地模式 3.3 远程模式 4 安装前准备 <!-- 整合hive --><property><name>hadoop.proxyuser.root.hosts</name><v…

Java+Swing: 主界面组件布局 整理9

说明&#xff1a;这篇博客是在上一篇的基础上的&#xff0c;因为上一篇已经将界面的框架搭好了&#xff0c;这篇主要是将里面的组件完善。 分为三个部分&#xff0c;北边的组件、中间的组件、南边的组件 // 放置北边的组件layoutNorth(contentPane);// 放置中间的 Jtablelayou…

Tair(3):Tair入门demo

新建一个maven项目 1 导入依赖 <dependency><groupId>com.taobao.tair</groupId><artifactId>tair-client</artifactId><version>2.3.5</version></dependency><dependency><groupId>com.alibaba</groupId>…

Linux权限(用户角色+文件权限属性)

Linux权限 文章目录 Linux权限一.文件权限1.快速掌握修改权限的方法&#xff08;修改文件权限属性&#xff09;2.对比权限的有无&#xff0c;以及具体的体现3.修改权限的第二套方法&#xff08;修改用户角色&#xff09;4.文件类型&#xff08;Linux下一切皆文件&#xff09; 二…

049:VUE 引入jquery的方法和配置

第049个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

springboot基础(80):redis geospatial的应用

文章目录 前言redis geospatial如何从地图上获取经纬度springboot 的相关方法调用准备redis服务器引用的依赖预设位置的keyGEOADD 添加位置GEORADIUS 获取指定经纬度附件的停车场&#xff08;deprecated&#xff09;GEORADIUS 获取指定成员附件的停车场&#xff08;deprecated&…

文心一言API(高级版)使用

文心一言API高级版使用 一、百度文心一言API(高级版)二、使用步骤1、接口2、请求参数3、请求参数示例4、接口 返回示例 三、 如何获取appKey和uid1、申请appKey:2、获取appKey和uid 四、重要说明 一、百度文心一言API(高级版) 基于百度文心一言语言大模型的智能文本对话AI机器…

归并排序--分治法

代码 #include<iostream> using namespace std;void merge(int arr[], int p, int q, int r, int temp[]) {int i p;int j q 1;int k 0;while (i < q && j < r){if (arr[i] < arr[j]){temp[k] arr[i];}else{temp[k] arr[j];}}while (i < q){t…

智能优化算法应用:基于蚁狮算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蚁狮算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蚁狮算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蚁狮算法4.实验参数设定5.算法结果6.参考文献7.MA…

ptmalloc:从内存虚拟化说起

前言 本文并不局限于ptmalloc的原理&#xff0c;而是从linux的内存虚拟化和系统调用原理出发&#xff0c;结合各种语言实现&#xff0c;讲明内存分配方面的trade off&#xff0c;力图事无巨细&#xff0c;追根究底。本文内容包括但不限于&#xff1a;NIO原理、0拷贝原理、内存…

leetcode:643. 子数组最大平均数 I(滑动窗口)

一、题目 链接&#xff1a;643. 子数组最大平均数 I - 力扣&#xff08;LeetCode&#xff09; 函数原型&#xff1a; double findMaxAverage(int* nums, int numsSize, int k) 二、思路 滑动窗口&#xff1a; 先计算数组前k个元素总和&#xff0c;作为第一个窗口&#xff0c;默…

vlog如何降低重复率

大家好&#xff0c;今天来聊聊vlog如何降低重复率&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff1a; vlog如何降低重复率 Vlog作为一种流行的视频日志形式&#xff0c;常常被人们用于记录日常生活、分享经…

pta模拟题——7-34 刮刮彩票

“刮刮彩票”是一款网络游戏里面的一个小游戏。如图所示&#xff1a; 每次游戏玩家会拿到一张彩票&#xff0c;上面会有 9 个数字&#xff0c;分别为数字 1 到数字 9&#xff0c;数字各不重复&#xff0c;并以 33 的“九宫格”形式排布在彩票上。 在游戏开始时能看见一个位置上…

Lambda表达式规则,用法

Lambda表达式是JDK8新增的一种语法格式 1.作用 简化匿名内部类的代码写法 Lambad用法前提&#xff1a;只能简化函数式接口&#xff08;一般加有Funcationallnterface&#xff09;&#xff08;有且仅有一个抽象方法&#xff09;的匿名内部类 匿名内部类&#xff1a;(本质是对…