【关于库函数的模拟实现】——strlen,strcpy,strcmp,,strcat,strstr,memcpy,memmove

前言

字符串操作函数是C语言中非常重要的函数,里面包括了指针的精华,同时对学习数据结构,如链表,数组,有非常好的练手方法。同时,知道内部实现,是基础中的基础。所以学习字符串操作函数是深入学C的必经之路。

my_strlen()的实现

关于my_strlen()函数想必大家已经很熟悉了,此函数用于获取字符串长度,并返回长度数值。
算法思想:用while循环逐个扫描每个字符,同时变量i自增+1;当扫描到结束符时,c[i]=0,自动跳出循环,此时i的值即为字符串长度。

接下来看看代码

#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str)//加const不可修改的字符指针,增加代码的可读性
{
	int count = 0;
	assert(str);//不要忘记断言
	while (*str != '\0')//以\0为读取结束标志
	{
		count++;
		str++;
	}
	return count;
 }
int main()
{
	char arr[] = "hello world!";
	int len = my_strlen(arr);//调用函数
	printf("%d\n", len);
	return 0;
}

再提醒下大家的就是断言,要记得引头文件#include<assert.h>

my_strcpy()的实现

my_strcpy()函数是将后者字符串复制给前者字符串,内置两个参数,前者为指向数组的指针,后者可以是指向数组的指针,也可以是字符串常量。
上代码

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, char* str)
{
	char* ret = dest;
	assert(dest && str)//一样的断言
	while (*dest++ = *str++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[] = "hello world!";
	char arr2[20] = { 0 };
	my_strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

my_strcmp()的实现

my_strcmp()函数用于比较两个字符串大小,实质逐个比较每个字符的ASCII值。大于则返回1;等于则返回0;小于则返回0;若一直相等,则直到一方扫描结束为止。
上代码

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
	char arr1[] = "hello world";
	char arr2[] = "hello bit";
	int ret = my_strcmp(arr1, arr2);
	printf("%d\n", ret);
	return 0;
}

my_strcat()的实现

my_strcat()函数是将两个字符串进行追加,目标字符串要包括’\0’,并且目标函数的大小一定要足够大,以保证源头字符串能够插入,同时源头字符串也同样要包括‘\0’
实际上my_strcat()的原理大致是mystrlen()和my_strcpy()结合而来的。
为什么这么说呢?

因为:
1,逐个扫描前者字符串直到结束符位置,并记录结束符位置的下标(类似于mystrlen()函数的思想)
2,逐个扫描后者字符串,并逐个往前者字符串后面一次赋值,直到扫描到后者字符串结束符位置,最后给前者字符串加上结束符。(类似于mystrcpy()函数的思想)

上代码

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* str)
{
	assert(dest && str);
	char* ret = dest;
	//找目标空间中的‘\0’
	while (*dest != '\0')
	{
		dest++;
	}
	//拷贝
	while (*dest++ = *str++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world!";
	//追加
	my_strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

my_strstr()的实现

my_strstr()函数是查找字符串的子串,找到后返回子串首元素之后的元素。
核心算法思想:
1、strstr() 函数搜索一个字符串在另一个字符串中的第一次出现。
2、找到所搜索的字符串,则该函数返回第一次匹配的字符串的地址;
3、如果未找到所搜索的字符串,则返回NULL。

上代码

#include<stdio.h>
char* my_strstr(const char* str1, const char* str2)
{
	char* s1 = NULL;
	char* s2 = NULL;
	char* cp = str1;
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "hello world";
	char arr2[] = "wor";
	char* p = my_strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", p);
	}
	return 0;
}

my_memcpy()的实现

主要针对两字符串无重叠的情况,这个也要根据编译器来决定,在(VS2019和VS2022)是可以实现有重叠的现象的。这里就不多解释,重点解释下一段代码喔

上代码

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
void* my_memcpy(void *dest, const void *src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	while(num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	int sz = sizeof arr1 / sizeof arr1[0];
	int len = sizeof(arr1);
	int i = 0;
	my_memcpy(arr2, arr1, len);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr2[i]);
	}
	printf("\n");
	return 0;
}

my_memove()的实现

首先,使用memove进行重叠字符串的拷贝大致可分为两种情况:
1.从前向后拷贝:当src内存位置高于dest
在这里插入图片描述
2.从后向前拷贝:当src内存位置低于dest
在这里插入图片描述
上代码

#include<stdio.h>
#include<assert.h>
void my_memmove(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);//确保不是空指针,用到指针都要想起这个
	if (dest < src)//得分两种情况,前-->后
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else//后-->前
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}
void test()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1 + 5, arr1, 20);//意思是,将arr1覆盖给arr1+5
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}
int main()
{
	test();
	return 0;
}

总结:
当我们dest的地址小于src的地址时我们就采用从前向后拷贝
当我们dest的地址大于src但是小于src+count的地址我们采用的从后向前拷贝
当我们的dest大于src+count的地址的时候从前从后拷贝都可以
所以当我们模拟实现这个函数的时候
就把它分成两种情况而定dest<src和dest>=src这两种情况讨论就行了。

![在这里插入图片描述](https://img-blog.csdnimg.cn/7669cfad2e9f4d56bfdf38011e3bf03b.png

😍好啦,本次分享到这里就结束了,欢迎各位佬来指正小白做的不好的地方,感谢品读,持续关注喔

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LearnLe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值