C语言中一些有关字符串的常见函数的使用及模拟实现(2)

在编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了\n⼀系列库函数,接下来我们就学习⼀下这些函数。

在上一篇博客中已经讲解了strlen,strcpy,strcmp,stccat这几个字符串相关的函数。

接着,再为大家介绍几个库函数,

strncpy,strncat,strncmp

同样包含在头文件string.h中

这三个函数都只是在中间加了个"n",现在,来详细认识一下这三个库函数。

文章目录

strncpy函数

看名字就知道,strncpy函数与strcpy函数是比较相似的,都是将一个字符串拷贝到另一个字符串中,不一样的是strncpy参数中多一个size_t类型的参数

这个参数的意思就是限制这个字符串的拷贝

这个例子就表示拷贝前5个字符,

来模拟实现一下这个库函数。

c 复制代码
//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函数就是有限制的去追加一个字符串

看一个例子帮助理解

直接来看代码实现吧。

c 复制代码
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类型。

来看一下这个函数的模拟实现

c 复制代码
#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,别慌,我们有解决方案,只需要做一个标记,下一次查找时直接从标记的下一个字符开始查找

c 复制代码
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类型的,表示这不仅可以拷贝字符串,也可以拷贝数字数组了。

如下:

来看一下它的模拟实现

c 复制代码
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

这里我们把模拟实现的代码放在这里,感兴趣的可以看一看。

从前向后拷贝和从后向前拷贝的方式时不一样的,所以要分类讨论一下

c 复制代码
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;
}

这就是几个字符串的简单讲解了,希望你能通过我的文章收获一些知识。

相关推荐
老猿讲编程15 分钟前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk1 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*1 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue1 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man1 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
萧鼎3 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸3 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农3 小时前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^3 小时前
数据库连接池的创建
java·开发语言·数据库
秋の花3 小时前
【JAVA基础】Java集合基础
java·开发语言·windows