字符串查找函数和错误信息报告函数

前言:

本博客介绍了字符串查找函数(strstr、strtok)和错误信息报告函数(strerror)


字符串查找函数(strstr、strtok)的介绍及其应用:

strstr函数的介绍及其模拟实现

strstr函数的介绍及其应用:

strstr函数的设计:const char * strstr (const char *str1 , const char * str2)

  1. 用法:在一个字符串中查找另一个字符串是否存在,若存在,返回的是子串第一次出现的位置,否则,返回空指针
  2. strstr的头文件是:#include <string.h>
  3. 提示:每段代码的注释都具有详细解释功能

strstr的应用:

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

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "bcd";
	char* p = strstr(arr1, arr2);
	if (p == NULL)
		printf("不存在\n");
	else
		printf("%s\n", p);
	return 0;
}

效果:


 strstr函数的模拟实现:

思路:

因为要模拟实现strstr函数(在字符串(在此代码里也就是str1)里查找字符串(在此代码里也就是str2)),所以很自然我们会想到把指针解引用,然后逐个对比。

    如果str2就在str1的开头,或者是只需要查找一次,不需要回退就能查找出来,那么这种做法是可取的。

    可是,如果str2不在str1的开头呢,又或者需要回退再次查找呢?这种做法显然不适用了。

    比如左边最后一个图,只有当str1落在第二个b时,才是真正符合条件的情况,而它指向第一个b的时候,这个b和下面str2的第一个字符一样,如果此时让str1++,str2++,那么,后面的str1里是b,而str2里是c,所以str1的第一个b的位置显然不是我们要找的位置,

    所以str2需要退回到开头,重新来过,而str1则是要退回到起始位置,现在所举的例子里是只要往回退一个字节就能回到起始位置(第一个b的位置),如若使用了循环,这样在跳过了很多字符的时候,我们根本无法判断str1此时的位置离初始位置的字节数,也无法知晓要往回退几个字节,以及如何实现

    于是乎,我们便再创建一个指针变量,在它里面放s1没有往后移时的位置(也就是起始位置),确保这个位置可以快速被找到。当发生上面要往回退的情况时,我们便可以直接让p++(因为上面那种状况已经表示s1的初始位置,也就是p的位置不是我们要找的位置,++让p往后移一个位置),再通过s1=p把p后移过的位置赋给s1,重新开始刚才的循环,另一边,我们也要让s2回到str2的位置重新开始

关于何时停止查找:

一种情况是str1已经遍历完了,但是还是找不到str2里的字符串,此种情况可以用*p='\0'来表示,*p已经移到了'\0'(也就是str1的最后一个元素了,字符都已经对比完了,没有和str2一样的),这种情况的时候就返回NULL

还有一种情况就是找到了,所谓找的了就是str2已经完全遍历完了,str2指到了'\0',这种情况就返回p的地址即可,因为后面打印的是str1里的字符串

#include <stdio.h>

char* my_strstr(const char* str1, const char* str2)
{
	const char* s1 = str1;
	const char* s2 = str2;
	const char* p = str1;
	while (*p)
	{
		s1 = p;
		s2 = str2;
		while (*s1 && *s2 && (*s1 == *s2))
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return p;//找到了
		}
		p++;
	}
	return NULL;//找不到
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "bcd";
	char* p = my_strstr(arr1, arr2);
	if (p == NULL)
		printf("不存在\n");
	else
		printf("%s\n", p);
	return 0;
}

strtok函数的介绍及其应用:

strtok的函数设计:char strtok ( char * str, const char * sep);

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

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

  3. strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针

  4. 注意:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容且可以修改;strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置;strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记

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

  6. strtok的头文件是:#include <string.h>
  7. 提示:每段代码的注释都具有详细解释功能

strtok的应用:

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

int main()
{
	char arr[] = "zfhejfie@kdjsedu.com";
	char buf[200] = { 0 };
	strcpy(buf, arr);

	const char* p = "@.";
	char* str = strtok(buf, p);
	printf("%s\n", str);

	char* src = strtok(NULL, p);
	//第一个参数指定一个字符,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记
	//strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针
	//注意:
	//strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容且可以修改
	//strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置
	//strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记
	//如果字符串中不存在更多的标记,则返回NULL指针

	//因为上述,所以在非第一次使用strtok时(在同一个字符串里)strtok的第一个参数都应该是NULL
	printf("%s\n", src);

	char* ste = strtok(NULL, p);
	printf("%s\n", ste);
	//切完整个字符串以后再调用时就会返回NULL

	//如果想要切两个字符串就直接不传NULL,可以将另外一个字符串像第一个字符串一样切,不一定要全切完才能换一个字符串切
	return 0;
}

效果:

 注释的解释如下图:

strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容且可以修改​​​​​​​;strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置;strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记

 

更加简洁的写法:

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

int main()
{
	char arr[] = "zfhejfie@kdjsedu.com";
	char buf[200] = { 0 };
	strcpy(buf, arr);//拷贝

	const char* p = "@.";//@.无所谓先后顺序
	char* str = NULL;
	for (str = strtok(buf, p); str!=NULL;str=strtok(NULL,p))
	//for(初始化;             判断条件; 做出的改变)
	{
		printf("%s\n", str);
	}
	return 0;
}


错误信息报告函数(strerror)的介绍及其应用:

strerror函数的介绍及其应用:

strerror的函数设计:char * strerror (int  error);​​​​​​​

  1. strerror的头文件是:#include <string.h>
  2. 提示:每段代码的注释都具有详细解释功能

strerror的应用:

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

int main()
{
	printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));

	return 0;
}

效果:

使用场景:

#include <stdio.h>
#include <errno.h>
int main()
{
	
	//如果调用失败的话,fopen(是一个库函数)就会把错误码记录到错误码的变量errno(C语言提供的全局变量)中(下一次的错误会把上一次的错误信息冲掉)
	//头文件:#include <errno.h>
	FILE* pf = fopen("test.txt", "r");//"r"--->read(读取)
	if (pf == NULL)//表示打开失败
	{
			//perror
			//void perror (const char * str )
			//perror=printf+strerror
			perror("fopen");//两个函数的好坏看需求,需求为大
			//打印结果:fopen: No such file or directory
			//会把错误信息直接打印出来
			//同时可以在前面加上一些自定义的信息(如:fopen)
			//你想要加上什么自定义的信息就直接在括号里面用双引号括起来
			//perror会在打印的时候省去双引号,加上冒号
			//详见上面的例子应该会更好分析
			//其实它也会换行
			//打印的依然是errno变量错误码对应的错误信息


			//printf("%d\n",errno);//打印出2--->对应的错误信息就是找不到文件
		printf("%s\n", strerror(errno));
		//因为我们并没有创建这样的一个文件,
		//所以必然打开(调用)失败
		//fopen就会把错误码记录到一个错误的变量errno中
		//而要想知道是什么错误导致我们无法打开这个文件的话(假设我们之前不知道为什么法发生错误)
		//我们就需要使用strerror这个函数
		//将errno这个变量传进去
		//然后再打印

		return 1;
	}

	//读文件
	fclose(pf);//关闭文件
	pf = NULL;
	return 0;
}

效果:

​​​​​​​


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值