C语言-字符串函数的实现(五)之strstr
C语言中的字符串函数有如下这些
- 获取字符串长度
- strlen
- 长度不受限制的字符串函数
- strcpy
- strcat
- strcmp
- 长度受限制的字符串函数
- strncpy
- strncat
- strncmp
- 字符串查找
- strstr
- strtok
- 错误信息报告
- strerror
字符串查找
strstr
还是一样,先看看如何使用它,对吧哈哈哈。
int main()
{
char* p1 = "abcdef";
char* p2 = "def";
// 在abcdef中找找def,找到的话返回它的地址,找不到返回空指针
char* rest = strstr(p1, p2);
if (rest == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", rest);
}
return 0;
}
老规矩,我们还是看看文档是怎样说的,如下
char * strstr ( const char * str1, const char * str2 );
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
返回一个指针,它指向str2,该str2是在str1中第一次出现的str2,或者一个空指针,如果str2不是str1的子串。
The matching process does not include the terminating null-characters, but it stops there.
这个匹配过程不包含'\0',但是它会停在那里。
实现
我们需要想想,它是如何实现字符串查找的?
有两个字符串,str1和str2,在str1中查找str2,那么我们需要两个指针p1和p2来进行,p1指向str1开头,p2指向str2开头,然后获取字符一一比较。
如果*p2为'\0'那么说明str2是空字符串,不能进行比较,就返回p1,即返回str1的地址。
如果*p2不为'\0',就说明不是空字符串,同时,也要判断*p1是否为空字符串,不是就可以进行查找。
查找的话,此时,我就通过*p1 == *p2判断*p1等于*p2?等于就都进行偏移,即p1++和p2++,然后继续判断,这里就成了一个循环,一直循环,直到它们两个不相等跳出循环。跳出循环后,如果*p2 等于'\0',说明已经查找到了,直接返回p2就好。如果*p2 不等于'\0',那么就p1就进行偏移,往后移动,继续判断,这里也形成了一个循环。到这里,基本的逻辑就这样了。
下面看看代码的实现。
断言指针不为空是个好习惯~
char* my_strstr(const char* p1, const char* p2)
{
// 保证指针的有效性,所以assert
assert(p1 != NULL);
assert(p2 != NULL);
// 如果p2是空字符串,那就比不了
if (*p2 == '\0')
{
printf("空字符串比不了,返回p1");
return p1;
}
// 真正的查找实现
while (*p1) // 判断*p1是'\0'吗?不是就可以查找
{
//while (*p1 == *p2) // 判断*p1等于*p2?等于就都进行偏移
while ((*p1 != '\0') && (*p2 != '\0') && (*p1 == *p2) ) // 继续完善,*p1,*p2都不能是\0,遇到\0就结束了,没东西可比了
{
p1++;
p2++;
}
if (*p2 == '\0')
{
// 说明匹配到了
return p2;
}
p1++; // 不等于,那么p1往后偏移
}
}
是的,到这里还没有结束,上面看似可以进行匹配了,但是代码还是有问题,比如遇到这种情况的时候
int mian()
{
char* p1 = "abbbcdef";
char* p2 = "bbc";
char* rest = my_strstr(p1, p2);
return 0;
}
第一个字符串的第一个字符a与第二个字符串的第一个字符b进行比较,发现不相等,那么p1就进行偏移,p1往后移动
此时b与b相比,相等,那么p1和p2都进行偏移,都往后移动
还是b与b相比,相等,继续偏移
此时b与c相比,不相等,那么p1进行偏移,此时p1指向的就是第五个字符c了,后面继续比较下去,肯定都不相等,也就是说找不到bbc,但是第一个字符串里明明有bbc,就是找不到,这就是会出现的问题。
那如何解决这个问题?
我们知道,如果可以让p1重新回去第二个字符的位置开始比较,那么肯定就能够找到bbc,但是上面的代码中,使p1发生改变了,p1不知道第二个字符b的位置,直接从第五个字符c的位置开始了。
所以,要解决的话,我们就需要一个变量记录从哪个位置开始匹配的,然后我们不要去改动p1,同时保险起见,也不要改动p2,那么我们就可以搞多两个指针变量s1和s2,作为p1和p2的拷贝,对这两个变量进行操作,就OK了~然后搞多一个变量current,作为当前需要移动的指针。
char* my_strstr(const char* p1, const char* p2)
{
// 保证指针的有效性,所以assert
assert(p1 != NULL);
assert(p2 != NULL);
// p1,p2不要往后动
// 需要一个变量记录从哪个位置开始匹配
//char* s1 = p1; // 这里赋值无所谓,就给NULL好了
char* s1 = NULL;
char* s2 = NULL;
char* current = (char*)p1; // 这里强制类型转换,因为p1是const修饰,赋值给了char*这个没有保护的,所以强转下,不然会报警告
// 如果p2是空字符串,那就比不了
if (*p2 == '\0')
{
printf("空字符串比不了,返回p1");
return (char*)p1;
}
// 真正的查找实现
while (*current) // 判断*current是'\0'吗?不是就可以查找
{
s1 = current;
s2 = (char*)p2;
while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
// 说明匹配到了
return current; // 返回子串地址
}
if (*s1 == '\0')
{
// 如果子串比较长,那么肯定是找不到的
return NULL;
}
current++; // 不等于,那么current往后偏移
}
return NULL; //找不到子串
}
C语言-字符串函数的实现(五)之strstr的更多相关文章
- 13-C语言字符串函数库
目录: 一.C语言字符串函数库 二.用命令行输入参数 回到顶部 一.C语言字符串函数库 1 #include <string.h> 2 字符串复制 strcpy(参数1,参数2); 参数1 ...
- C语言字符串函数大全
C语言字符串函数大全 函数名: stpcpy 功 能: 拷贝一个字符串到另一个 用 法: char *stpcpy(char *destin, char *source); 程序例: #include ...
- C语言-字符串函数的实现(一)之strlen
C语言中的字符串函数有如下这些 获取字符串长度 strlen 长度不受限制的字符串函数 strcpy strcat strcmp 长度受限制的字符串函数 strncpy strncat strncmp ...
- C语言-字符串函数的实现(二)之strcpy
C语言中的字符串函数有如下这些 获取字符串长度 strlen 长度不受限制的字符串函数 strcpy strcat strcmp 长度受限制的字符串函数 strncpy strncat strncmp ...
- C语言字符串函数例子程序大全 – string相关
关于字符串函数的应用细则,例子程序 – jerny 函数名: stpcpy 功 能: 拷贝一个字符串到另一个 用 法: char *stpcpy(char *destin, char *source) ...
- 关于C语言字符串函数使用的一点心得
就字符串的拼接函数为例strcat. 原型:extern char *strcat(char *dest,char *src);用法:#include <string.h> 功能:把src ...
- 07 --C语言字符串函数
1)字符串操作 复制 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strdup(char *str) 将串拷贝到新建的位置处 ...
- C语言字符串函数
strtok() 字符串分割函数strstr() 字符串查找函数 范例 #include <string.h> main() { char * s = " ...
- c语言字符串函数大全(转)
函数名: stpcpy 功 能: 拷贝一个字符串到另一个 用 法: char *stpcpy(char *destin, char *source); 程序例: #include <stdio. ...
随机推荐
- django学习-11.开发一个简单的醉得意菜单和人均支付金额查询页面
1.前言 刚好最近跟技术部门的[产品人员+UI人员+测试人员],组成了一桌可以去公司楼下醉得意餐厅吃饭的小team. 所以为了实现这些主要点餐功能: 提高每天中午点餐效率,把点餐时间由20分钟优化为1 ...
- RTPS解析
资料参考: https://blog.csdn.net/HBS2011/article/details/102520704
- SSL/TLS协议详解(上):密码套件,哈希,加密,密钥交换算法
本文转载自SSL/TLS协议详解(上):密码套件,哈希,加密,密钥交换算法 导语 作为一名安全爱好者,我一向很喜欢SSL(目前是TLS)的运作原理.理解这个复杂协议的基本原理花了我好几天的时间,但只要 ...
- 第28天学习打卡(Date和Calendar类 基本类型的包装类 集合 增强for循环 )
Date和Calendar类 简介 日期和日历类,用于操作日期相关信息. 构造方法 Date(): 构造一个日期对象,当前系统时间,精确到毫秒. Date(long): 构造一个日期对象,时间为自&q ...
- Linux就该这样学--之常用linux命令及bash基础
Linux就该这样学--之常用linux命令及bash基础 Linux命令 管道 重定向 环境变量 常用命令 常用系统工作命令 系统状态检测命令 工作目录切换命令 文本文件编辑命令 文件目录管理命令 ...
- 开发过程中遇到的js知识点总结,面试题等,持续更新
1.Object.freeze() 方法用于冻结一个对象,即将对象设置为不可扩展.将对象的所有自有的属性和方法(包括Symbol值的属性和方法)配置为不可配置,不可写. Object.freeze( ...
- Windows下常用测试命令
(1)ping 127.0.0.1 (测试本地网卡,127.0.0.1是本地循环地址,如果本地址无法Ping通,则表明本地机TCP/IP协议不能正常工作) (2)ping 127.0.0.1 - ...
- CVE-2016-10033 WordPress <= 4.6 命令执行漏洞
漏洞参考 https://www.jianshu.com/p/85ac4af9f947 漏洞信息 这个锅还是要PHPMailer背(CVE-2016-10033,WordPress 使用 PHPMai ...
- Codeforces Round #683 (Div. 2, by Meet IT)
A 初始情况\(1\) ~ \(n\)堆分别有 \(1\) ~ \(n\) 个糖果,第\(i\)次操作给除了所选堆的糖果数 \(+ i\), 找到一种方案可以使得所有堆糖果数相同,输出操作次数和每次选 ...
- FreeBSD 12.2 已经发布 从现有版本更新到12
#freebsd-update -r 12.2-RELEASE upgrade 如果提示更新第三方软件后,再执行freebsd-update install , 请输入 #pkg update &am ...