当前位置: 首页 > news >正文

【C语言】常见的字符串函数

©作者:末央&

©系列:C语言初阶(适合小白入门)
©说明:以凡人之笔墨,书写未来之大梦

在这里插入图片描述

目录

  • strlen函数
    • 模拟实现
  • strstr子串查找函数
    • 模拟实现
  • strtok字符串分割

strlen函数

strlen函数是一个用于求字符串长度的库函数。它的参数是被求长度的字符串的起始地址,返回值是一个无符号整型。

注意:

1.参数指向的字符串要以’\0’结束。
2.trlen返回的是在字符串中’\0’之前出现的字符个数(不包含’\0’)。
3.注意函数的返回值为size_t,是无符号的(易错)。

模拟实现

方式一:计数器的方式
我们定义一个变量为count,如果传入的指针指向的内容不是’\0’,那么count++,同时指针后移一位,循环往复,直到找到’\0’时返回count即可。

size_t my_strlen1(const char* str)
{size_t count = 0;//计数器while (*str){count++;str++;}return count;
}

方式二:递归的方式
我们一进入函数体就判断传入指针指向的内容是否为’\0’,如果是就返回0,不是就返回1+my_strlen2(str+1),如此进行下去,直到递归到内层时找到’\0’,这时再一步步将值返回回来即可。

size_t my_strlen2(const char* str)
{if (*str == '\0')return 0;elsereturn 1 + my_strlen2(str + 1);
}

方式三:指针-指针的方式
进入函数体时,我们事先定义一个指针变量将传入的指针保存下来,然后将传入的指针向后移,直到遇到’\0’时,我们返回当前指针与保存的指针的差值即可。(指针与指针的差的绝对值是两个指针之间的元素个数)

size_t my_strlen3(const char* str)
{const char* p = str;//保存起始位置while (*str != '\0')str++;return str - p;
}

strstr子串查找函数

char *strstr( const char *string, const char *strCharSet );

strstr函数可以在一个字符串(字符串1)中查找另一个字符串(字符串2),如果字符串2存在于该字符串1中,那么就返回被字符串2在字符串1中第一次出现的起始位置,如果在字符串1中找不到字符串2,那么就返回空指针(NULL)。它的第一个参数是字符串1的起始位置,第二个参数是字符串2的起始位置。
注意:

若字符串2为空字符串,则返回字符串1的起始位置。
举个例子,比如我们在字符串"abcdefbcd"中查找字符串"bcd"。

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "abcdefbcd";char arr2[] = "bcd";char* ret = strstr(arr1, arr2);//在arr1中查找arr2字符串第一次出现的位置if (ret != NULL)printf("%s\n", ret);elseprintf("找不到\n");return 0;
}

注意:strstr函数的返回值是字符串"bcd"在字符串"abcdefbcd"中第一次出现的位置的起始位置,而不是出现几次就返回几个起始位置。

模拟实现

这里讲一下下面代码中各个指针的作用。

  • cur指针,主要记录每次主串开始匹配的位置,为了防止子串和主串第一次没有匹配成功,而方便多次匹配。如果这次没匹配成功,则cur++开始从下一个位置匹配。

  • -p1和sp指针: 通过判断s1和s2指针解引用后是否相等来判断每个字符是否匹配成功,若成功,则指针后移比较下一对字符;若失败,p1指针返回cp指针处,p2指针返回待查找字符串的起始位置

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);if (*str2 == '\0')		//空串{return str1;}const char* cur = str1;const char* p2 = str2;		//不改变字符加constconst char* p1 = str1;while (*cur){p1 = cur;p2 = str2;while (*p1 == *p2 && *p1 && *p2)		//这里判断p1是为了判断下一个字符是否为\0,节省循环次数{p1++;p2++;}if (*p2 == '\0'){return cur;}cur++;}return NULL;//不是子串}
int main()
{char arr1[] = "abbbcdef";char arr2[] = "bbc";char* ret = my_strstr(arr1, arr2);if (ret == NULL){printf("%s不是字串\n",arr2);}else{printf("%s\n", ret);}return 0;
}

在这里插入图片描述

strtok字符串分割

char *strtok( char *strToken, const char *strDelimit );
  • strtok函数能通过给定的一系列字符将一个字符串分割成许多子字符串的函数。它的第一个参数是需要被分割的字符串的首地址;第二个参数是一个字符串的首地址,该字符串是用作分隔符的字符集合。返回值是查找到的标记的首地址。

  • 注意:

    strtok函数找到strToken中的一个标记时,会将其用 \0结尾并返回这个标记的首地址。

  • strtok函数会改变strToken函数,所以在使用strtok函数切分的字符串都是临时拷贝的内容并且可修改。

  • strtok函数的第一个参数不为NULL时,函数将找到strToken中的第一个标记,并保存它在字符串中的位置。

  • strtok函数的第一个参数为NULL时,函数将从同一个字符串中被保存的位置开始查找它的下一个标记。

  • 若字符串中不存在更多的标记,则返回NULL指针。

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "2957055542@qq.com";//待分割字符串char arr2[] = "@.";//分隔符的字符集合char arr3[20] = { 0 };strcpy(arr3, arr1);//将数据拷贝一份使用,防止原数据被修改char* token = strtok(arr3, arr2);//第一次传参需传入待分割字符串首地址while (token != NULL)//说明还未分割完{printf("%s\n", token);token = strtok(NULL, arr2);//对同一个字符串进行分割,第二次及以后的第一个参数为NULL}return 0;
}

注意:当strtok函数找到第一个标记时,将其后的’@‘字符改为’\0’并返回第一个标记的首地址,所以我们以返回的地址为首地址开始打印字符串的时候就只会打印出2957055542,第二次再对该字符串调用strtok函数时将从’@'字符后面开始寻找下一个标记。

相关文章:

  • 雷池WAF+Modsecurity安装防护及系统加固
  • 【Qwen2部署实战】Qwen2初体验:用Transformers打造智能聊天机器人
  • 【面试题】IPS(入侵防御系统)和IDS(入侵检测系统)的区别
  • 人脸特征68点识别 C++
  • 哪吒汽车,正在等待“太乙真人”的拯救
  • 监听 web 容器内的网络请求
  • vCenter VXR01405C ALARM Certificate is about to expire
  • 【python】scikit-learn安装失败No matching distribution found for scikit-learn
  • 【数据库原理】总结(期末版)
  • 机器学习 C++ 的opencv实现SVM图像二分类的训练 (二)【附源码】
  • 我在高职教STM32——GPIO入门之按键输入(1)
  • .net core 的缓存方案
  • 特别有用!配置Overall_Elapsed后,大大提升您使用fiddler的工作效率!
  • 【Python爬虫】Python爬取喜马拉雅,爬虫教程!
  • Golang | Leetcode Golang题解之第204题计数质数
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • ES6--对象的扩展
  • ES6系统学习----从Apollo Client看解构赋值
  • HashMap剖析之内部结构
  • JAVA之继承和多态
  • PhantomJS 安装
  • session共享问题解决方案
  • socket.io+express实现聊天室的思考(三)
  • SpringCloud集成分布式事务LCN (一)
  • 彻底搞懂浏览器Event-loop
  • 对象管理器(defineProperty)学习笔记
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 来,膜拜下android roadmap,强大的执行力
  • 力扣(LeetCode)22
  • 区块链技术特点之去中心化特性
  • 为视图添加丝滑的水波纹
  • 物联网链路协议
  • 写给高年级小学生看的《Bash 指南》
  • 异常机制详解
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • Spring第一个helloWorld
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • #window11设置系统变量#
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (6)设计一个TimeMap
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第1节 (全局数据、栈和堆)
  • (备忘)Java Map 遍历
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (十五)使用Nexus创建Maven私服
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)h264中avc和flv数据的解析
  • (转)Oracle存储过程编写经验和优化措施