在编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了\n⼀系列库函数,接下来我们就学习⼀下这些函数。
在上一篇博客中已经讲解了strlen,strcpy,strcmp,stccat这几个字符串相关的函数。
接着,再为大家介绍几个库函数,
strncpy,strncat,strncmp
同样包含在头文件string.h中
这三个函数都只是在中间加了个”n“,现在,来详细认识一下这三个库函数。
文章目录
- strncpy函数
- strncat函数
- strncmp函数
- strstr函数
- memcpy函数
strncpy函数
看名字就知道,strncpy函数与strcpy函数是比较相似的,都是将一个字符串拷贝到另一个字符串中,不一样的是strncpy参数中多一个size_t类型的参数
这个参数的意思就是限制这个字符串的拷贝
这个例子就表示拷贝前5个字符,
来模拟实现一下这个库函数。
//strncpy的函数模拟实现
#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* s1,const char* s2,size_t n)
{
assert(s1 && s2);
char* ret = s1;
while (n--&&(*s1 = *s2))
{
s1++;
s2++;
}
return ret;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[20] = "ghijk";
char*ret = my_strncpy(arr1, arr2, 3);
printf("%s", ret);
return 0;
}
strncat函数
相信你在了解了strncpy函数之后,就大概可以猜出来strncat函数就是有限制的去追加一个字符串
看一个例子帮助理解
直接来看代码实现吧。
char* my_strncat(char* s1, char* s2, size_t n)
{
assert(s1 && s2);
char* ret = s1;
while (*s1 != '\0')
{
s1++;
}
while (n-- && (*s1 = *s2))
{
*s1++;
*s2++;
}
return ret;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[20] = "ghijk";
char*ret = my_strncat(arr1, arr2, 1);
printf("%s", ret);
return 0;
}
strncmp函数
⽐较str1和str2的前num个字符,如果相等就继续往后⽐较,最多⽐较num个字⺟,如果提前发现不⼀样,就提前结束,⼤的字符所在的字符串⼤于另外⼀个。如果num个字符都相等,就是相等返回0.
看上面这个例子,因为只比较了前四个字符,是相等的,所以返回0
该函数的返回类型是int类型。
来看一下这个函数的模拟实现
#include<stdio.h>
#include<assert.h>
int my_strncmp(const char* str1, const char* str2,size_t num)
{
int ret = 0;
assert(str1 != NULL);
assert(str2 != NULL);
while (*str1 == *str2&&num--)
{
if (num == 0)
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[10] = "abcdef";
char arr2[10] = "abcdfg";
int ret = my_strncmp(arr1,arr2,3);
printf("%d", ret);
return 0;
}
strstr函数
strstr函数是字符串中寻找子字符串的一个库函数。该函数的返回类型是char*类型,返回的是找到子字符串的第一个元素的地址,例如,在abcdef中查找一个cde,返回字符c的地址。
该函数返回类型是char*类型。
这个函数的模拟实现比之前略微增加一些难度,比如你在abcccdef中查找ccd,别慌,我们有解决方案,只需要做一个标记,下一次查找时直接从标记的下一个字符开始查找
char* my_strstr(const char* s1, const char* s2)
{
assert(s1 && s2);//asser断言检查s1,s2是否是空指针
char* cur = s1;//cur作为一个标记
char* a1 = NULL;
char* a2 = NULL;
while (*cur)//cur到'\0'是还没有找到子字符串则返回空指针NULL。
{
a1 = cur;//从第二个字符开始遍历查找
a2 = s2;
while (*s1&&*s2&&*a1 == *a2)
{
*a1++;
*a2++;
}
if (*a2 == '\0')//子字符串到'\0'时,表示找到了,返回指针cur
return (char*)cur;
cur++;
}
return NULL;
}
memcpy函数
这个函数又比strncpy函数高级了一点,它的参数和返回类型都都是void类型的,表示这不仅可以拷贝字符串,也可以拷贝数字数组了。
如下:
来看一下它的模拟实现
void* my_memcpy(void* s1, const void * s2, size_t n)
{
assert(s1 && s2);
void* ret1 = s1;
while (n--)
{
*(char*)s1 = *(char*)s2;
*((char*)s1)++;
*((char*)s2)++;
}
return ret1;
}
我们自己模拟实现的函数能否自己拷贝自己呢?
很明显,这是与我们想达到的效果是不一样的,它不能自己拷贝自己。
原因是当把1,2拷贝到3,4上时,3,4被改变成了1,2.所以不能自己拷贝自己。
但是库函数可以实现这个功能。
但是memcpy函数本身就没有要求自己拷贝自己,所以,我们的函数模拟实现还是没有问题的。
可以说编译器实现的库函数还是很厉害的。
C语言也有一个专门用来自己拷贝自己的库函数memmove
这里我们把模拟实现的代码放在这里,感兴趣的可以看一看。
从前向后拷贝和从后向前拷贝的方式时不一样的,所以要分类讨论一下
void* my_memmove(void* dest, const void* str, size_t n)
{
assert(dest && str);
void* ret = dest;
if (dest < str)
{
while (n--)
{
*((char*)dest) = *((char*)str);
(char*)dest = (char*)dest + 1;
(char*)str = (char*)str + 1;
}
}
else
{
while (n--)
{
*(((char*)dest)+n) = *(((char*)str)+n);
}
}
return ret;
}
这就是几个字符串的简单讲解了,希望你能通过我的文章收获一些知识。