目录
- 前言
- strlen
- strlen的模拟实现
- strcpy
- strcat
- strcat的模拟实现
- strcmp
- strcmp的模拟实现
- strncpy
- strncat
- strncmp
- strstr
- strchr和strrchr
- strstr的模拟实现
前言
本章我们将重点介绍处理字符和字符串的库函数的使用和注意事项。
strlen
我们先来看一个我们最熟悉的求字符串长度的库函数–strlen
#include <stdio.h>
#include <string.h>
int main()
{
int len = strlen("abcdef");
printf("%d", len);
return 0;
}
运行结果如图1
这里有几点是值得我们注意的:
- 字符串已 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ ).
- 参数指向的字符串必须要以‘\0’结束。
- 注意函数的返回值是size_t,是无符号的。
strlen的模拟实现
模拟实现strlen的方法有很多种,例如计数器方法,递归方法,指针减去指针的方法,我们以指针减指针为例。
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
int count = 0;
assert(str);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[100] = "abcdef";
int ret = my_strlen(arr);
printf("%d", ret);
return 0;
}
strcpy
库函数strcpy在之前的博客中有十分详细的讲解,这里就不做过多赘述了
模拟实现库函数–strcpy
这里我们只需要注意以下几点即可
-
源字符串必须以 ‘\0’ 结束。
-
目标空间必须足够大,以确保能存放源字符串.
如图2就是错误示范
-
目标空间必须可变
如图3就是错误示范
strcat
stract函数的作用是将一段字符串追加到另一端字符串的末尾。
代码实现如下
int main()
{
char arr1[20] = "Hello ";
char arr2[20] = "World";
strcat_s(arr1, arr2);
printf("%s", arr1);
return 0;
}
其中arr1是被追加对象,而arr2是追加对象。运行结果如图4
我们知道在Hello 的末尾有一个\0,那么在arr2追加的时候有没有将这个\0给覆盖掉呢,我们主动添加一个\0来看效果。
int main()
{
char arr1[20] = "Hello \0********";
char arr2[20] = "World";
strcat_s(arr1, arr2);
printf("%s", arr1);
return 0;
}
我们调试一下观察变化,如图5,6
我们发现\0是被覆盖掉了的。所以在追加的时候是从\0开始的。
我们在使用这个函数的时候要注意以下几点
- 源字符串必须以 ‘\0’ 结束。
- 目标空间必须有足够的大,能容纳下源字符串的内容.
- 目标空间必须可修改.
strcat的模拟实现
我们先来看代码
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
//将最初的arr1的首元素地址保存起来
char* ret = dest;
//找目标空间中的\0
while (*dest != '\0')
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "Hello ";
char arr2[20] = "World";
my_strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
我们通过画图来分析一下:
strcat可以自己给自己追加吗?
这需要用到后面优化过后的strncat函数,strcat函数本身是不适合自己追加自己的,这是因为每当覆盖过后,\0会消失,*dest找不到\0了,于是会继续往下找,这样就会陷入一个死循环当中。
strcmp
相信strcmp的作用读者应该也是再熟悉不过了,它的作用就是比较两个字符串大小。
举两个简单的例子
arr1 = "abcdef";
arr2 = "bbd";
strcmp(arr1,arr2);
a大于b所以返回一个大于0的数
arr1 = "abcdef";
arr2 = "abad";
strcmp(arr1,arr2)
从第一个元素开始依次比较,前两个元素都相等,到第三个是,由于a的ascll码值比b大,所以arr2大于arr1,返回一个小于0的数
为什么返回的值是大于小于零的数呢?因为标准规定:
- 第一个字符串大于第二个字符串,则返回大于0的数字
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字
由此可见,strcmp的返回值必须要用有符号类型接收
strcmp的模拟实现
先来看代码
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2)
while (*str1 == *str2)
{
if(*str1 == '\0')
return 0;
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[20] = "adq";
int ret = my_strcmp(arr1, arr2);
printf("%d", ret);
return 0;
}
以上面代码为例,比较结果如图7
所以arr2是小于arr1的。
前面我们介绍的库函数都是长度不受限制的函数,是不安全的,所以在c语言中还引入了一系列长度受到限制了的字符串函数,下面我们继续来介绍长度受限制的字符串函数。
strncpy
strncpy在传递参数的时候就要比strcpy函数多传递一个数参数,意思是只拷贝这么多个参数。
int main()
{
char arr1[] = "abcdef";
char arr2[5] = "xxx";
strncpy(arr2, arr1, 3);
printf("%s", arr2);
return 0;
}
代码运行结果如图8
这样相对来讲就会更安全一些。
strncat
有了刚刚strncpy对于对于参数的理解,这个函数理解也大同小异
int main()
{
char arr1[20] = "hello ";
char arr2[] = "abcdef";
strncat_s(arr1, arr2, 3);
printf("%s", arr1);
return 0;
}
追加的结果如图9
通过这个函数,我们就能实现字符串自己对自己追加的效果,因为多了一个长度的限制,所以可以避免死循环导致程序崩溃的情况。
strncmp
在strncmp中的个数代表的是要比较几个元素,看下面这段代码
int main()
{
char arr1[20] = "abcdef ";
char arr2[] = "abcqqq";
int ret = strncmp(arr1, arr2, 3);
printf("%d", ret);
return 0;
}
由于只比较了三个元素,所以比较的结果应该是相等的,返回值应该为0,运行结果如图10
strstr
这个函数的作用是在str1中找str2出现第一次的位置。找到了就返回首次出现的地址。没找到就返回空指针。
先来看代码
int main()
{
char arr1[] = "abcdef";
char arr2[] = "bcd";
char* p = strstr(arr1, arr2);
if (p == NULL)
{
printf("找不到");
}
else
{
printf("%s", p);
}
return 0;
}
strchr和strrchr
strchr和strstr的效果很类似,是在str1中找一个字符首次出现的位置,而strrchr是找这个字符在str1中最后一次出现的位置。
对这两个函数分别举一个例子:
int main()
{
char arr1[] = "abcdef";
char a = 'b';
char* p = strchr(arr1, a);
if (p == NULL)
{
printf("找不到");
}
else
{
printf("%s", p);
}
return 0;
}
打印结果如图11
int main()
{
char arr1[] = "abcdebf";
char a = 'b';
char* p = strrchr(arr1, a);
if (p == NULL)
{
printf("找不到");
}
else
{
printf("%s", p);
}
return 0;
}
打印结果如图12
strstr的模拟实现
代码如下
char* my_strstr(const char* str1, const char* str2)
{
char* s1 = NULL;
char* s2 = NULL;
char* cp = (char*)str1;
while (*cp)
{
s1 = cp;
s1 = (char*)str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdebf";
char arr2[] = "cde";
char* p = my_strstr(arr1, arr2);
if (p == NULL)
{
printf("找不到");
}
else
{
printf("%s", p);
}
return 0;
}
我们通过图解来分析,如图13
以上就是本章全部内容,如有出入,欢迎大佬们指正。