学习笔记6:字符串库函数(下)

news/2024/10/23 7:32:45/

目录

一. strstr模拟实现

二. strtok模拟实现

三.关于strerror和perror的说明


一. strstr模拟实现

库函数strstr函数首部:char * strstr ( const char *str1, const char * str2);

函数的功能是在str1指向的主字符串中寻找子串str2,并且返回主字符串中子字符串第一次出现的位置(主字符串中第一个子字符串的首地址)。

如果主字符串中找不到子字符串则函数返回空指针。

函数的实现思路是暴力遍历法:

用两层循环来实现,外层循环用一个循环变量i遍历主字符串str1,每当在主字符串中找到子字符串的首元素就进入第二层循环进行两个字符串的匹配,若匹配失败,指针i回溯到匹配的起始位置继续寻找下一个子串首字符,重复上述步骤。

内层循环以两个字符串的终止符或不相等的对应字符为结束标志。

匹配成功的标志是内层循环维护子串str2的指针指向子串str2的终止符。

模拟实现:(这里使用str1和str2的指针运算代替下标i和j的运算)

char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);if (!(*str2))                     如果子串为空字符串则返回主串的首地址{return (char*)str1;}const char*  RE1 = NULL;          用于记录str1指针回溯的位置const char*  RE2 = str2;          用于记录str2指针回溯的位置while (*str1)                     找到主串中的\0则停止循环{RE1 = str1;while (*str1++ == *str2++){if (!(*str2))             匹配子串中的\0则代表在主串中找到了子串{return (char*)RE1;}if (!(str1))              匹配过程中找到主串的\0则函数直接返回NULL{return NULL;}}str1 = RE1;str2 = RE2;                   str1,str2指针回溯str1++;}return NULL;
}

另外一种可读性更好,思路更加清楚的写法:

char* my_strstr2(const char* str1, const char* str2)
{assert(str1 && str2);if (!(*str2))                     如果子串为空字符串则返回主串的首地址{return (char*)str1;}const char* pstr2 = str2;         pstr1和pstr2用于内层循环进行字符串匹配const char* pstr1 = str1;while (*str1){pstr1 = str1;                 令pstr1和pstr2指向进行字符串匹配的起始位置pstr2 = str2; while (*pstr1 && (*pstr1 == *pstr2)){                             找到匹配过程中的终止字符或不相等的对应字符后跳出循环pstr1++;pstr2++;if ('\0' ==*pstr2 )        只有在匹配过程中pstr2指向子字符串终止符才算匹配成功{return (char*)str1;}}str1++;}return NULL;
}                                     此种写法很容易进行越界检查和思路梳理

测试代码:

int main()
{char arr1[] = "acdsdssdsfdgdh";char arr2[] = "fdg";char* retlib = strstr(arr1, arr2);char* retmy = my_strstr(arr1, arr2);char* retmy2 = my_strstr2(arr1, arr2);if (retlib || retmy || retmy2){printf("%s\n", retlib);printf("%s\n", retmy);printf("%s\n", retmy2);}return 0;
}

二. strtok模拟实现

库函数strtok函数首部: char * strtok ( char * str, const char * sep );

1.sep参数是个字符串,定义了用作分隔符的字符集合;

2.第一个参数指定一个字符串,它包含了0个或者多个sep字符串中的字符作为分割标记;

3.strtok函数找到str中的分割标记(sep字符串中的字符),并将其用 \0 替换,返回一个指向这个分割出来的子串的指针(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改);


4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个分割标记,strtok函数将保存它在字符串中的位置


5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记;


6.如果字符串中不存在更多的标记,则返回 NULL 指针;

 

模拟实现strtok: 

char* my_strtok(char* String, const char* label)
{assert(label);static flag = 1;           用于标记被分割的主串是否被完全遍历static char* Mark = NULL;  用于记录被分割主串中的分割位置if (flag && !String)       第一次传空指针则返回空指针,以及后续主串若已经被完全遍历再次调 用该函数时则返回空指针 {return NULL;   }else if (String)               传入的String为非空指针时(传入新的被分割主串){flag = 0;                      重置flagMark = NULL;                   重置Markchar* ret = String;            记录分割段的起始位置const char* plabel = label;    plabel用于遍历分隔符字符串while (*String){plabel = label;while (*plabel && *plabel != *String){plabel++;}if (*plabel)          若在主串中找到分割符,则完成分割操作{*String = '\0';Mark = String;return ret;}String++;}flag = 1;                  从这里跳出循环代表主串已经被完全遍历,flag标记为1return ret;}else{char* pString = Mark+1;       用pSring作为继续遍历主串的指针变量char* ret = Mark + 1;         记录分割段的起始位置const char* plabel = label;   plabel用于遍历分隔符字符串while (*pString){plabel = label;while (*plabel && *plabel != *pString){plabel++;}if (*plabel)         若在主串中找到分割符,则完成分割操作{*pString = '\0';Mark = pString;return ret;}pString++;}flag = 1;                从这里跳出循环代表主串已经被完全遍历,flag标记为1return ret;}
}

测试代码: 

int main()
{char str1[] = "sdf@cc.gif@bit";char str2[] = "sdf@cc.gif@bit";char str3[] = "sdf@cc.gif@bit";char str4[] = "sdf@cc.gif@bit";char label[] = "@.";char* pstr = NULL;for (pstr = strtok(str1, label); pstr != NULL; pstr = strtok(NULL, label)){printf("%s\n", pstr);}printf("-----------\n");for (pstr = my_strtok(str2, label); pstr != NULL; pstr = my_strtok(NULL, label)){printf("%s\n", pstr);}printf("-----------\n");for (pstr = strtok(str3, label); pstr != NULL; pstr = strtok(NULL, label)){printf("%s\n", pstr);}printf("-----------\n");for (pstr = my_strtok(str4, label); pstr != NULL; pstr = my_strtok(NULL, label)){printf("%s\n", pstr);}printf("-----------\n");return 0;
}

三.关于strerror和perror的说明

sterror函数首部:char * strerror ( int errnum );
C语言标准库中有一个全局整形变量errno,当用户调用库函数发生错误时,库函数会将错误码(一个整形数值)存在errno中,将errno作为实参传入strerror函数中就可以将错误码(一个整形数值)翻译为对应的错误信息,并以字符串首地址的形式返回给用户,用户可以将描述错误信息的字符串打印出来。

比如打开文件时,用于检查是否发生错误可以调用该函数。

#include <stdio.h>
#include <string.h>
#include <errno.h>//必须包含的头文件
int main ()
{FILE * pFile;pFile = fopen ("unexist.ent","r");if (pFile == NULL) {printf ("Error opening file unexist.ent: %s\n",strerror(errno));}//errno: Last error numberreturn 0;
}

perror函数首部:void perror( const char *string ) ;

形参中的const char *string是用户传入的自定义信息,perror函数可以自动访问全局变量errno,并将错误信息和用户传入的自定义信息一起打印出来,使用起来更加方便。

比如打开文件时,用于检查是否发生错误也可以调用该函数。

#include <stdio.h>
#include <string.h>
#include <errno.h>//必须包含的头文件
int main ()
{FILE * pFile;pFile = fopen ("unexist.ent","r");if (pFile == NULL) {perror("error message :");}return 0;
}

 


http://www.ppmy.cn/news/10115.html

相关文章

【经典面试题】

TC经典面试题1.赛马问题 WY经典面试题2.:烧香问题 砝码称重问题 有36匹马&#xff0c;6个跑道&#xff0c;在没有计时器的情况下&#xff0c;至少需要赛马多少次&#xff0c;才能比出前三名&#xff1f; 答案&#xff1a;至少需要比较8次。 解题思路&#xff1a; 先把36匹…

2023年中职网络安全竞赛Windows操作系统渗透测试解析(超详细)

B-12:Windows操作系统渗透测试 任务环境说明: 服务器场景:Server2305(关闭链接)服务器场景操作系统:Windows(版本不详)通过本地PC中渗透测试平台Kali对服务器场景进行系统服务及版本扫描渗透测试,并将该操作显示结果中445端口对应的服务版本信息字符串作为Flag值提交…

c++入门(命名空间+缺省参数+函数重载)

文章目录1. 命名空间1. c语言的两个域2. 命名空间的使用1.类型问题命名空间A和B的实现2. 变量问题3.三种访问方法1.指定命名空间访问2. 全局展开using namespace std 的含义尽量不使用using namespace std的原因3. 部分展开2. 缺省参数(备胎)1. 概念2.全缺省参数3.半缺省参数错…

【07】概率图推断之信念传播

概率图推断之信念传播 文章目录将变量消除视为信息传递信息传递算法加总乘积信息传递因子树上的加总乘积信息传递最大乘积信息传递总结在《概率图推断之变量消除算法》中&#xff0c;我们讲了变量消除算法如何对有向图和无向图求P(Y∣Ee)P(Y \mid E e)P(Y∣Ee)的边缘概率。 …

IDEA启动项目通过https进行访问,nginx配置https访问

一、IDEA启动项目通过https进行访问 1、获取证书 证书申请网络有很多方法&#xff0c;这里腾讯云的nginx版证书举列 2、证书转换 springboot是识别p12证书的&#xff0c;所有这里需要吧pem证书进行转换。转换工具OpenSSL-Win64&#xff08;自行百度下载&#xff09;下载完…

一步步实现React-Hooks核心原理

React Hooks已经推出一段时间&#xff0c;大家应该比较熟悉&#xff0c;或者多多少少在项目中用过。写这篇文章简单分析一下Hooks的原理&#xff0c;并带大家实现一个简易版的Hooks。 这篇写的比较细&#xff0c;相关的知识点都会解释&#xff0c;给大家刷新一下记忆。 Hooks…

回顾2022年的历程,展望2023年目标

这里写目录标题回顾2022年博客之星你参加了吗&#xff1f;学习方面写博客方面在涨粉丝方面展望2023回顾2022年 时间如梭&#xff0c;转眼间已经2023年了。 你开始做总结了吗&#xff1f; 博客之星你参加了吗&#xff1f; 这是 2022 博客之星 的竞选帖子&#xff0c; 请你在这…

非对称加密实战(一):JDK生成keystore获取公钥私钥及代码验证【附源码】

目录使用说明非对称加密生成keystore文件公钥私钥互相解密获取fd-alias.keystore中的公钥私钥使用生成公钥私钥进行解密源码地址使用说明 非对称加密 非对称加密算法主要有&#xff1a;RSA、Elgamal、背包算法、Rabin、D-H、ECC&#xff08;椭圆曲线加密算法&#xff09;。下…