【C语言】字符串函数介绍三(strstr、strtok、streeror)

前言

之前我们用两篇文章介绍了strlen、strcpy、stract、strcmp、strncpy、strncat、strncmp这些函数

第一篇文章strlen、strcpy、stract

第二篇文章strcmp、strncpy、strncat、strncmp

今天我们就来学习:

话不多说,我们直接开始

strstr

返回值

如果s2是s1的子串,就返回子串的首元素地址,
如果没找到,就返回空指针

补充说明

当s1中存在多个s2时,其返回的地址,是s2在s1中第一次出现的地址

一般情况

int main()
{
	char* p1 = "abcdefabcdef";
	char* p2 = "def";
	char * ret = strstr(p1, p2);
	if (ret == NULL)
	{
		printf("0\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

模拟实现

基本思路

两种情况:
*s1 == *s2
*s1 != *s2

*s1 == *s2

s1向后移动,s2也向后移动,看是否继续相等

while (*s1 == *s2)
{
	s1++;
	s2++;
}

*s1 != *s2

s1不动,s2向后移动一位,看二者是否相等

while (*s1 == *s2)
{
	s1++;
	s2++;
}
s1++;

问题1

当s2是’\0‘时,说明要查找的字符串已经结束了,这时就结束查找

问题2

当s1是’\0‘时,说明被查找的字符串已经结束了,这时就结束查找

问题3

当我们真的找到这个子串的时候,想要返回首元素地址,却发现s2指向的是字串的最后一个元素。

问题4

当字符串1为“abbbc”,字符串2为“bbc”时,
是得不到正确结果的,因为s2指向的已经是第二个b了,s1指向的也是第二个b

解决方案

想解决问题三和四,就单独创建两个变量p1、p2来存储s1和s2就行了

并且,当s1和s2指向的元素相等时,要创建一个变量cur来记录这个位置,方便s1和s2回到这个位置继续查找。

最终代码

char* my_strstr(const char* s1, const char* s2)
{
	assert(s1 && s2);
	if (*s2 == 0)//当s2是空字符串时,传进来的s2是‘\0’
	{
		return (char*)s1;//此时直接返回s1即可
	}
	
	char* p1 = s1;
	char* p2 = s2;
	char* cur = s1;

	while (*cur)
	{
		p1 = cur;
		p2 = s2;
		while ((*p1 == *p2) && (*p1 != '\0') && (*p2 != '\0'))
		{
			p1++;
			p2++;
		}
		if (*p2 == '\0')
		{
			return cur;
		}
		cur++;
	}
	return NULL;

}

int main()
{
	char* p1 = "abcdef";
	char* p2 = "def";
	char* ret = strstr(p1, p2);
	if (ret == NULL)
	{
		printf("0\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

写的还是比较清晰的,有疑问可以在文章下面留言~

strstr函数在编译器中的实现

我没在库里找到这个文件,所以在网上复制了一份源码

#include char * __cdecl strstr(const char *str1, const char *str2)
{
    char *cp = (char *)str1;
    char *s1, *s2;if (!*str2)
        return((char *)str1);while (*cp)
    {
        s1 = cp;
        s2 = (char *)str2;while (*s2 && !(*s1 - *s2))
            s1++, s2++;if (!*s2)
            return(cp);
​
        cp++;
    }return(NULL);
}int main(int argc, char *argv[], char *envp[])
{
    char str[] = "asfasfas";
    char *p = "asas";
    char ret = '0';
    ret = strstr(str, p);
    if (ret != NULL)
    {
        printf("%c", ret);
    }
    else
    {
        printf("NULL");
    }
    return 0;
}

补充说明,在源代码中,我们可以看到参数都用const保护起来了,所以在返回值那里需要进行强制类型转换(char*)
//虽然不转换代码也能运行,但还是严谨一点好

拓展

KMP算法和上面的实现过程结果是一样的,但更高级,感兴趣的可以去了解一下

strtok(会用即可)

介绍

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

详细解释

下面我们看一段代码,来实际应用一下

int main()
{
	char arr[] = "[email protected]";
	char* p = "@.";

	char buff[10000] = { 0 };
	strcpy(buff, arr);

	char* ret = strtok(arr, p);
	printf("%s\n", ret);

	return 0;
}

1.p就是sep,里面的字符就是分隔符

2.arr就是str

3.strtok函数会从str开始,逐个向后查找,当找到sep中的分隔符时,strtok就将它改成’\0’,并返回分割出的这个字符串的首元素地址。
下一次查找就从\0后面开始寻找(等于是创建了一个静态变量存储’\0’后面的元素的地址)

4.当第二个参数不为NULL时,从sep中的的第一个分隔符开始查找

5.当第二个参数为NULL时,那就进入sep中的下一个分隔符开始查找
意思就是:查找第二个分隔符

6.当字符串str中遇到\0时,就结束查找,并返回NULL

注意:

strtok函数会破坏被查找的字符串,所以我们需要将原字符串拷贝一份,再进行查找

实际应用

像上文那样使用的话,有几个字符串,就得写几次
但实际上,我们并不会像上面那段代码那样使用strtok函数,

在上文“详细解释”中,第六点提到:当str中遇到\0时,就返回NULL

所以我们可以先创建一个变量ret定义为NULL
使用for循环来打印出分割的多个字符串

	for (ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\n", ret);
	}

(很神奇的一种使用方式)

strerror

介绍

char * strerror ( int errnum )

返回错误码,所对应的错误信息

使用方法

传入一个整数,输出一个地址

int main()
{
	char* str = strerror(0);
	printf("%s\n", str);

	return 0;
}

运行结果:
【C语言】字符串函数介绍三(strstr、strtok、streeror)_第1张图片

此处传入的整数,被称为错误码

每个错误码,都对应一个错误信息
如:
0:No error
1:Operation not permitted

实际使用

但在实际应用中,错误码不会由我们传入,而是输入errno,
errno是一个全局的错误码变量
当C语言的库函数在执行过程中,发生了错误,就会把对应的错误码,赋值给errno
需要包含头文件

举例

C语言中我们使用fopen函数来打开一个文件

int main()
{
	FILE* pf = fopen("test.txt", "r");
	//要打开文件的名称是test.txt,打开方式是"r",读取这个文件
	//这个函数会返回一个FILE*的指针
	if (pf == NULL)
	//当返回为空指针,说明读取失败
	//但读取失败有很多原因,可能是文件不存在,可能是访问权限不够等等
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		printf("open file success\n");
	}

	return 0;
}

这里我们就可以通过strerror函数,来找到确切的原因
运行结果

没有这样的文件或目录

【C语言】字符串函数介绍三(strstr、strtok、streeror)_第2张图片

errno

想知道更多可以直接转到定义查看不同的整数对应的错误信息

【C语言】字符串函数介绍三(strstr、strtok、streeror)_第3张图片

结语

字符串函数就介绍到这里了,下一篇文章我们会学习字符分类函数
我们明天见~

你可能感兴趣的:(C语言知识点,c语言,开发语言)