字符串函数的模拟实现

引言:对于字符串来说,我们通常想要对其完成各种各样的目的,不管是排序还是查找都是最普遍的功能,而我们的C语言中也包含着一系列函数是为了实现对字符串的一些功能,今天我们就来介绍他们。


strlen函数:

求字符串的长度(也就是求一个字符串的'\0'前面有多少个字符)

#include<stdio.h>
#include<string.h>
int main(){char* str = "abcdef";int b = strlen(str);printf("%d\n", b);
return 0;
}

 

这个就是strlen最常用的,用来求一个字符串的长度,那么我们是否可以不用库函数,自己模拟一个strlen呢🤔
#include<stdio.h>
#include<string.h>
//方法一:计数法
size_t my_strlen1(char* str) {int count = 0;while (*str) {count++;str++;}return count;
}
int main(){char* str = "abcdef";int c = my_strlen1(str);printf("%d\n", c);
return0;
}

方法一:计数法,利用for循环,用count计数,当str遇到'\0'的时候循环结束,跳出循环,返回count的值。

#include<stdio.h>
#include<string.h>
//方法二:递归法
size_t my_strlen2(char* str) {if (*str == '\0')return 0;else return 1+my_strlen2(str+1);
}
int main() {char* str = "abcdef";int d = my_strlen2(str);printf("%d\n", d);
return 0;
}

 方法二:递归法,利用递归思想,当没有遇到'\0'的时候,就再次调用该函数,直到str遇到'\0',返回0,然后依次再重新返回,就计算出了字符串的长度。

#include<stdio.h>
#include<string.h>
//方法三:指针-指针
size_t my_strlen3(char* str) {char* p = str;while (*p != '\0') {p++;}return p - str;
}
int main(){char* str = "abcdef";int e = my_strlen3(str);printf("%d\n", e);return 0;
}

方法三:指针-指针,我们先将字符串的首元素地址记为str,再将首元素地址传给p,利用while循环找到最后一个元素的地址,当(结束地址-首元素地址)即为字符串长度。

 可以看我们四种方法的运行结果,都是可以正确的求出字符串‘acbdef的长度.

strcpy函数:

#include<stdio.h>
#include<string.h>
int main(){char arr1[20] = { 0 };char arr2[] = "Hello";strcpy(arr1, arr2);printf("%s\n", arr1);return 0;
}

这个函数的作用就是将arr2中的字符串拷贝到arr1中。那么我们该如何对他进行模拟实现呢🤔

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
char* my_strcpy(char* dest, const char* src) {char* ret = dest;while (*dest++ = *src++){;}return ret;
}
int main(){char arr1[20] = { 0 };char arr2[] = "Hello";//strcpy(arr1, arr2);my_strcpy(arr1, arr2);printf("%s\n", arr1);return 0;
}

 我们先将两个数组的首元素地址传给函数,因为最终要返回起始地址,所以先将dest给ret,然后运用while循环将src的每一项解引用后赋给dest,然后后置++再寻找下一个元素,直到src元素找到了'\0',然后循环跳出,返回起始地址ret。

我们把arr1打印出来可以看到确实是成功拷贝。 

strcmp函数:

比较的结果是:
如果str1>str2那么就返回一个>0的数 
如果str1<str2那么就返回一个<0的数
如果str1=str2那么就返回0
#include<stdio.h>
#include<string.h>
int main() {char arr1[] = { "abc" };char arr2[] = { "abdef" };int a = strcmp(arr1, arr2);if (a > 0) printf(">=");else printf("<");return 0;
}

这是一个简单的例子,因为d的ASC的值比c的ASC的值大,所以arr1<arr2,所以返回的是一个小于0的数,所以 打印出来的就是小于号。

那么我们来模拟实现实现一下这个函数

#include<stdio.h>
#include<string.h>
int my_strcmp(const char* dest, const char* src){while (*dest == *src) {if (*dest == 0) return 0;dest++;src++;}if (*dest > *src)return 1;else return -1;
}
int main() {char arr1[] = { "abc" };char arr2[] = { "abdef" };int a = my_strcmp(arr1, arr2);if (a > 0) printf(">=");else printf("<");return 0;
}

 首先,还是一样,先传值然后依旧是运用我们的while循环来进行遍历以及交换,当其中一个已经遍历完之后,会跳出while循环,然后开始判断当前元素谁大谁小,然后根据大小返回大于零还是小于零的数。

strcat函数:

#include<stdio.h>
#include<string.h>
int main() {char arr1[20] = { "abc"};char arr2[] = { "def" };//库函数自带的strcatstrcat(arr1, arr2);printf("%s\n", arr1);return 0;
}

 值得注意的是:

1、目标空间必须足够大,并且可以修改

2、目标空间中必须有\0,以便能够找到目标空间的末尾

3、源字符串中也得有\0,拷贝的时候要拷过去

那么我们如何对这个函数进行模拟实现呢🤔

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, char* src) {char* ret = dest;assert(dest && src);while (*dest != '\0') {dest++;}while (*dest++ = *src++) {;}return ret;
}
int main() {char arr1[20] = { "abc"};char arr2[] = { "def" };my_strcat(arr1, arr2);printf("%s\n", arr1);return 0;
}

 依然是传参,然后用第一个while循环找到目标空间中的\0然后,跳出循环,此时dest指向目标函数的末尾,然后进入第二个循环,src开始给dest进行赋值,直到src遇到\0,跳出循环,返回目标函数的起始地址,完成追加。

strstr函数: 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {char arr1[] = { "abcdefghi" };char arr2[] = { "def" };char* ret = strstr(arr1, arr2);if (ret == NULL) {printf("找不到");}else printf("%s", ret);return 0;
}

strstr是字符串查找函数,我们给函数传两个字符串的时候,他会拿源函数去和目标函数进行匹配,如果目标函数中有原函数那么,就返回段函数的起始地址,如果找不到,那么就会返回NULL

那么我们该如何模拟实现这一函数呢🤔

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
const char* my_strstr(const char* str1, const char* str2) {const char* sp;const char* s1;const char* s2;assert(str1 && str2);if (*str2 == '\0') {return str1;}sp = str1;while (*sp) {s1 = sp;s2 = str2;while (*str1 && *str2 && *s1 == *s2) {s1++;s2++;}if (*s2 == '\0')return sp;sp++;}return NULL;
}
int main() {char arr1[] = { "abcdefghi" };char arr2[] = { "def" };char* ret = my_strstr(arr1, arr2);if (ret == NULL) {printf("找不到");}else printf("%s", ret);return 0;
}

 可以看到,我们模拟实现的函数成功的查找到了目标函数中的def,并且返回了找到它的起始位置。那么具体的实现我来详细的讲解一下。 

如图,我们用s1和s2进行比较,
1️⃣如果两个相同就各自+1比较下一个,那么按照这样进行下去,当str2为0的时候,就证明已经找到了,如果str1已经为0,str2还没有为0那么就证明,str1里找不到str2。
2️⃣如果两个不同就sp++,然后sp再赋值给s1,这样就不会使得s1一直向前++而找不到原来的位置了,s2也是一样,当sp赋值给s1的时候,str2也同时赋值给s2,让s2能回到起始位置。
这样一直对比下去,直到s1或s2指向0,函数结束。那我们这个函数的模拟就算实现了,但是其实这是个笨方法,效率不高,如果大家感兴趣的话,可以去了解了解kmp算法。

strerror函数:

是用来打印错误码的函数

 

 

strtok函数:

是用来将一段字符串进行分割的函数

 

#include<stdio.h>
#include<string.h>
int main() {char arr[] = "haohao@xuexi@tiantian.xiangshang";char* p = "@.";char* s = NULL;for (s = strtok(arr, p); s != NULL; s = strtok(NULL, p)) {printf("%s\n",s);}return 0;
}

我们这里可以看到,strtok将arr里的字符串给分隔开了,这个函数可以把指定参数替换成'\0',这样就可以将那些干扰的字符给去掉,并将其一一打印出来了。 

 好了,今天我就给大家分享到这里,感谢大家的观看!!!

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

网课搜题 小猿题库多接口微信小程序源码 自带流量主

多接口小猿题库等综合网课搜题微信小程序源码带流量主&#xff0c;网课搜题小程序, 可以开通流量主赚钱 搭建教程1, 微信公众平台注册自己的小程序2, 下载微信开发者工具和小程序的源码3, 上传代码到自己的小程序 源码下载&#xff1a;https://download.csdn.net/download/m0_…

计算机网络笔记3 数据链路层

计算机网络系列笔记目录&#x1f447; 计算机网络笔记6 应用层计算机网络笔记5 运输层计算机网络笔记4 网络层计算机网络笔记3 数据链路层计算机网络笔记2 物理层计算机网络笔记1 概述 文章前言 &#x1f497; 站在巨人的肩膀上&#xff0c;让知识的获得更加容易&#xff01…

Python爬虫——爬虫基础模块和类库(附实践项目)

一、简单介绍 Python爬虫是使用Python编程语言开发的一种自动化程序&#xff0c;用于从互联网上获取信息。通过模拟浏览器的行为&#xff0c;爬虫可以访问网页、解析网页内容&#xff0c;并提取所需的数据。 python的爬虫大致可以分为通用爬虫和专用爬虫&#xff1a; 通用爬虫…

Linux 基本语句_5_创建静态库|动态库

静态库 创建主函数&#xff1a;main.c 应用函数&#xff1a;add.c、sub.c、mul.c 创建calc.h文件作为头文件 生成可执行文件*.o文件 gcc -c add.c -o add.o ....包装*.o文件为静态库 ar -rc libmymath.a add.o sub.o mul.o编译静态库并指明创建静态库的位置 sudo gcc mai…

Python操作MongoDb创建文档及CRUD基本操作

Python3中类的高级语法及实战 Python3(基础|高级)语法实战(|多线程|多进程|线程池|进程池技术)|多线程安全问题解决方案 Python3数据科学包系列(一):数据分析实战 Python3数据科学包系列(二):数据分析实战 Python3数据科学包系列(三):数据分析实战 MongoDB 操作手册----文档…

git提交代码实际操作

1.仓库的代码 2.克隆代码下存在的分支 git clobe https://gitee.com/sadsadasad/big-event-11.git 3.查看当下存在的分支 git branch -a 在很多情况下,我们是要围绕着dev分支进行开发,所以我们可以在开发之前问明白围绕那个分支进行开发。 4.直接拉去dev分支代码 5.如果没在…

程序三高的方法

程序三高的方法 目录概述需求&#xff1a; 设计思路实现思路分析1.1&#xff09;高并发 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,c…

安卓教材学习

文章目录 教材学习第一行代码 Android 第3版环境配置gradle配置下载包出现问题 教材学习 摘要&#xff1a;选了几本教材《第一行代码 Android 第3版》&#xff0c;记录一下跑案例遇到的问题&#xff0c;和总结一些内容。 第一行代码 Android 第3版 环境配置 gradle配置 gradl…

人机关系不是物理关系也不是数理关系

人机关系是一种复杂的社会技术系统&#xff0c;涉及到人类和机器、环境之间的相互作用和影响。它不仅限于物理接触和数理规律&#xff0c;同时还包括了思维、情感、意愿等方面的交流和互动。在人机关系中&#xff0c;人类作为使用者和机器作为工具&#xff08;将来可能会上升到…

【网站】让自己的个人主页能被Google检索

参考&#xff1a; https://zhuanlan.zhihu.com/p/129022264

JUC第十五讲:JUC集合-ConcurrentHashMap详解(面试的重点)

JUC第十五讲&#xff1a;JUC集合-ConcurrentHashMap详解 本文是JUC第十五讲&#xff1a;JUC集合-ConcurrentHashMap详解。JDK1.7之前的ConcurrentHashMap使用分段锁机制实现&#xff0c;JDK1.8则使用数组链表红黑树数据结构和CAS原子操作实现ConcurrentHashMap&#xff1b;本文…

1.3.OpenCV技能树--第一单元--图像的基础操作(基础篇)

文章目录 1.文章内容来源2.图像的基本操作2.1.图像加载2.2.图像显示2.3.数据读取2.4.截取图像2.5.颜色通道提取2.5.1.保留红色处理2.5.2.保留绿色处理2.5.3.保留蓝色处理 3.易错点总结与反思 1.文章内容来源 1.题目来源: 2.资料来源:https://edu.csdn.net/skill/opencv/opencv…

C++笔记之信号量、互斥量与PV操作

C笔记之信号量、互斥量与PV操作 文章目录 C笔记之信号量、互斥量与PV操作1.信号量概念2.信号量例程一3.信号量例程二4.信号量例程三5.互斥量6.PV操作概念7.PV操作详解——抄自&#xff1a;https://mp.weixin.qq.com/s/vvjhbzsWQNRkU7-b_dURlQ8.PV操作的英文全称 1.信号量概念 …

Vscode爆红Delete `␍`eslintprettier/prettier

一、先看报错 文件中爆红&#xff0c;提示 Delete ␍eslintprettier/prettier 二、解决方案 项目根目录下&#xff0c;.prettierrc.js 文件中&#xff1a; endOfLine: auto,三、重启VsCode 此时不在爆红&#xff0c;问题完美解决

云原生Kubernetes:简化K8S应用部署工具Helm

目录 一、理论 1.HELM 2.部署HELM2 3.部署HELM3 二、实验 1.部署 HELM2 2.部署HELM3 三、问题 1.api版本过期 2.helm初始化报错 3.pod状态为ImagePullBackOff 4.helm 命令显示 no repositories to show 的错误 5.Helm安装报错 6.git命令报错 7.CentOS 7 下git c…

Redis-双写一致性

双写一致性 双写一致性解决方案延迟双删&#xff08;有脏数据的风险&#xff09;分布式锁&#xff08;强一致性&#xff0c;性能比较低&#xff09;异步通知&#xff08;保证数据的最终一致性&#xff0c;高并发情况下会出现短暂的不一致情况&#xff09; 双写一致性 当修改了数…

【word】从正文开始设置页码

在写报告的时候&#xff0c;会要求有封面和目录&#xff0c;各占一页。正文从第3页开始&#xff0c;页码从正文开始设置 word是新建的 分出三节&#xff08;封面、目录、正文&#xff09; 布局--->分割符--->分节符--->下一页 这样就能将word分为3节&#xff0c;分…

深度学习-卷积神经网络-AlexNET

文章目录 前言1.不同卷积神经网络模型的精度2.不同神经网络概述3.卷积神经网络-单通道4.卷积神经网络-多通道5.池化层6.全连接层7.网络架构8.Relu激活函数9.双GPU10.单GPU模型 1.LeNet-52.AlexNet1.架构2.局部响应归一化&#xff08;VGG中取消了&#xff09;3.重叠/不重叠池化4…

Python 列表推导式深入解析

Python 列表推导式深入解析 列表推导式是 Python 中的一种简洁、易读的方式&#xff0c;用于创建列表。它基于一个现有的迭代器&#xff08;如列表、元组、集合等&#xff09;来生成新的列表。 基本语法&#xff1a; 列表推导式的基本形式如下&#xff1a; [expression for…

Android 开发错误集合

&#x1f525; 开发错误集合一 &#x1f525; Caused by: java.lang.ClassNotFoundException: Didnt find class "com.mask.app.ui.LoginRegisterActivity" on path: DexPathList[[zip file "/data/app/~~NMvHVhj8V6-HwGbh2amXDA/com.mask.app-PWbg4xIlETQ3eVY…