教会你使用并实现strstr与strtok:查找与切割

目录

strstr函数

strstr函数介绍

自定义实现strstr

strtok函数

strtok函数介绍

strtok参数讲解

strtok使用时的注意事项

for循环在strtok使用中的妙处

自定义实现strtok


strstr函数

strstr函数介绍

strstr(str1,str2)

作用:查找指定字符串

在字符串str1中查找是否含有字符串str2

如果有,返回str2在str1中第一次出现的地址

否则返回空指针NULL

注意:如果str2是一个空字符串,则返回str1

 函数声明:char * strstr (const char * str1, const char * str2)

由于只是进行查找而不改变原来的两个字符串,所以使用const修饰会更加安全

函数使用图示:

当找到第一个完全相同字符串后,返回该位置字符串的地址(并不会截断)

 自定义实现strstr

核心:

能找到:>

1、将str1首地址放入空瓶flag中

2、在str1中遍历,直到找到和str2首字符相同的字符,将此地址存入flag

3、找到第一个字符相同之后,str1和str2一起后移,依次判断后面的字符是否都相同

4、如果相同,则说明找到了,将flag中保存的地址进行return

如果找不到呢?

  在每一次经过上述的3 步骤之后,让flag往后移。

  直到碰到str1中的\0,说明str1遍历完都没找到与str2相同的字符串

  这时候返回NULL

#include <stdio.h>
char* my_strstr( const char* str1,  const char* str2)
{
	//断言是否为空指针
	assert(str1 && str2);
	const char*s1 = NULL;
	const char*s2 = NULL;
    //特殊情况(str2为空字符串)
    if(str2=='\0')
        return str1;
	//用flag记录str1中与str2相同字符的地址
	const char* flag = str1;
	//如果遍历str1都没有找到
	//直到flag为\0时,跳出while
	while (*flag)
	{
		s1 = flag;
		s2 = str2;
		//寻找相同字符
		while(*s1&&(*s1 == *s2))
		{
			s1++;
			s2++;
		}
		//如果最终遍历s2中来到\0
		//说明找到了与s2中相同的字符串
		if (*s2 == '\0')
			return (char*)flag;//此时将flag地址返回
		flag++;
	}
	return NULL;//找不到就返回空指针
}
int main()
{
	char arr1[] = "abcdefgabc";
	char arr2[] = "defg";
	printf("%s", my_strstr(arr1, arr2));
}

strtok函数

strtok函数介绍

头文件<string.h>

strtok(str,sep)

str表示字符串,sep就是Seperator意思是分割符,这里用来表示多个分割符的集合

作用:分割字符串,一次切割一段

示例如下:>


strtok参数讲解

char *strtok ( char* str , const char * delimiters )

第一个参数是需要切割的字符串。
该字符串中可以包含 0个、1个、多个分割符

第二个参数就是我们指定的切割符集合。

假设想要分别得到Hello,world,!

那么分隔符中就只需要有空格

如果要将以下字符串切割,那么分隔符中需要包含,;。这三个字符

 strtok使用时的注意事项

char *strtok ( char* str , const char * delimiters )

1、strtok函数找到str中的一个分割符之后,会将其用 \0 覆盖并且作为结尾,之后再返回一个指向这个\0的指针。

注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容。

char *strtok ( char* str , const char * delimiters )

2、第一次切割时,第一个参数(也就是str)不能是NULL

      第一次切割时,函数将找到str中第一个分割符,将它替换为\0

      同时strtok函数将保存这 个\0在整个字符串中的位置。

 char *strtok ( char* str , const char * delimiters )

3、第二次、第三次...第n次使用strtok函数切割同一个字符串时。

      第一个参数为NULL

      此时函数将从上一个保存的\0的位置开始往后切割,直到遇到下一个分割符或\0

 for循环在strtok使用中的妙处

for(初始化;循环条件的控制;循环条件的改变)
{

}

for循环中的初始化只执行一次。

而strtok函数在第一次使用时传递的第一个参数为字符串

之后传递的第一个参数都是NULL

利用for循环这一特性可以更好地使用strtok函数

int main()
{
	char arr[] = "C语言,Java;C++。hello world";
	char flag[] = ",;。 ";
	char* tmp = arr;
	char* ret = NULL;
	for (ret = strtok(tmp, flag); ret != NULL; ret = strtok(NULL, flag))
	{
		puts(ret);
	}
}

自定义实现strtok

核心:

第一次使用:

第一个参数为字符串。首先记录字符串首地址,接着将字符串挨个与分割符集合中的每个分割符进行比较,在字符串中找到了一个分割符之后就停止,返回字符串首地址,同时将该分割符置为\0,并且记录这个\0的地址。

第二次使用:

第一个参数为NULL。首先,将上一次查找之后的\0地址传递过来,从该\0的下一个位置开始,记为第二个字符串的首地址,再次遍历分割符之后找到某个分割符。将该分割符置为\0同时记录地址。

...

第N次使用同理。

(重点:函数需要能够记录上一次调用后保存的\0的位置,所以我们使用static用于记录)

代码如下:>

#include <stdio.h>
#include <string.h>

char* my_strtok(char* str1, const char* str2)
{
  static char* flag = NULL;//标记每一个分割符的位置
  static char* start = NULL;//每一次切割的字符串的首地址
  static int length = 0;
  static int count_str1 = NULL;//记下目前遍历过的字符总长度,与str1的长度进行比较
  int sz_delm = strlen(str2);//分隔符数量,循环遍历所有分隔符
//1、第一次进入时
  if (str1 != NULL)
  {
   length = strlen(str1);//保存整个str1的长度
   start = str1;//str1的首地址存入
   for (*str1; *str1 != '\0'; str1++)
    {
      for (int i = 0; i < sz_delm; i++)
       {
		if (i == 0) count_str1++;//每次查找时给count加1
		if (*str1 == *(str2 + i))
		{
		  *str1 = '\0';//将分割符置为\0
		  flag = str1;//将该分割符的地址保存下来
		  return start;
		}
		}
	}
  }
//2、之后的每一次进入函数时,第一个参数都是空指针
  else
  {
   start = flag + 1;
   str1 = start;
   //这里的for循环和第一次一样。
   for (*str1; *str1 != '\0'; str1++)
   {
	 for (int i = 0; i < sz_delm; i++)
	  {
		if (i == 0) count_str1++;
		if (*str1 == *(str2 + i))
		  {
			*str1 = '\0';//将分割符置为\0
			flag = str1;//记录这一次置0的位置。
			return start;
		  }
	  }
	}
//3、找不到分割符就返回NULL
	 if (count_str1 > length)
		 return NULL;
	 //保证每个控路都有返回值
	 return start;
	}
}

int main()
{
	char arr[50] = "C语言,Java;C++?OK";
	char* delm = ",;?";
	char* tmp = NULL;
	for (tmp = my_strtok(arr, delm); tmp != NULL; tmp = my_strtok(NULL, delm))
	{
		puts(tmp);
	}
}

 

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值