前言:
本博客介绍了字符串查找函数(strstr、strtok)和错误信息报告函数(strerror)
字符串查找函数(strstr、strtok)的介绍及其应用:
strstr函数的介绍及其模拟实现
strstr函数的介绍及其应用:
strstr函数的设计:const char * strstr (const char *str1 , const char * str2)
- 用法:在一个字符串中查找另一个字符串是否存在,若存在,返回的是子串第一次出现的位置,否则,返回空指针
- strstr的头文件是:#include <string.h>
- 提示:每段代码的注释都具有详细解释功能
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);
-
sep参数是字符串,定义了用作分隔符的字符集合
-
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记
-
strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针
-
注意:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容且可以修改;strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置;strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记
-
如果字符串中不存在更多的标记,则返回NULL指针
- strtok的头文件是:#include <string.h>
- 提示:每段代码的注释都具有详细解释功能
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);
- strerror的头文件是:#include <string.h>
- 提示:每段代码的注释都具有详细解释功能
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;
}
效果: