之前我们用两篇文章介绍了strlen、strcpy、stract、strcmp、strncpy、strncat、strncmp这些函数
第一篇文章strlen、strcpy、stract
第二篇文章strcmp、strncpy、strncat、strncmp
今天我们就来学习:
话不多说,我们直接开始
如果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也向后移动,看是否继续相等
while (*s1 == *s2)
{
s1++;
s2++;
}
s1不动,s2向后移动一位,看二者是否相等
while (*s1 == *s2)
{
s1++;
s2++;
}
s1++;
当s2是’\0‘时,说明要查找的字符串已经结束了,这时就结束查找
当s1是’\0‘时,说明被查找的字符串已经结束了,这时就结束查找
当我们真的找到这个子串的时候,想要返回首元素地址,却发现s2指向的是字串的最后一个元素。
当字符串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;
}
写的还是比较清晰的,有疑问可以在文章下面留言~
我没在库里找到这个文件,所以在网上复制了一份源码
#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算法和上面的实现过程结果是一样的,但更高级,感兴趣的可以去了解一下
- 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);
}
(很神奇的一种使用方式)
char * strerror ( int errnum )
返回错误码,所对应的错误信息
传入一个整数,输出一个地址
int main()
{
char* str = strerror(0);
printf("%s\n", str);
return 0;
}
此处传入的整数,被称为错误码
每个错误码,都对应一个错误信息
如:
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函数,来找到确切的原因
运行结果
没有这样的文件或目录
想知道更多可以直接转到定义查看不同的整数对应的错误信息
字符串函数就介绍到这里了,下一篇文章我们会学习字符分类函数
我们明天见~