学习笔记6:字符串库函数(下)
创始人
2024-05-08 04:54:29
0

目录

一. 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 
#include 
#include //必须包含的头文件
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 
#include 
#include //必须包含的头文件
int main ()
{FILE * pFile;pFile = fopen ("unexist.ent","r");if (pFile == NULL) {perror("error message :");}return 0;
}

 

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...