模拟实现字符串函数

目录

  • 模拟实现strlen
  • 模拟实现strcpy
  • 模拟实现strncpy
  • 模拟实现strcat
  • 模拟实现strncat
  • 模拟实现strstr
  • 模拟实现strcmp
  • 模拟实现strncmp
  • 模拟实现memcpy
  • 模拟实现memmove
    ##1.模拟实现strlen函数
strlen是计算字符串长度的函数,不包含'\0',我们要模拟实现这个函数,方法不止一种,这里解释三种方法:
方法一:计数器方式
int my_strlen(const char* arr)
{
	assert(arr);
	int count = 0;
	while (*arr++)//遍历
	{
		count++;//计数

	}
		return count;
}

方法二:递归(不创建临时变量)

int my_strlen(const char* arr)
{
	assert(arr);
	if (*arr == '\0')
		return 0;
	else
		return 1 + my_strlen(arr + 1);//根据递归的次数,每次加1
}

方法三:指针—指针

int my_strlen(const char* arr)
{
	assert(arr);
	char *p = arr;//先将起始位置存起来
	while (*p != '\0')
	{
		p++;//遍历得到指向'\0'前面位置的指针
	}
	return p-arr;//后-前得到的是中间元素的个数
}

注:指针减指针得到的是中间元素的个数。
##2.模拟实现strcpy函数

strcpy函数是将源字符串拷贝到目标字符串里
思路:我们要将源字符串拷贝到目标字符串里,必然要找到源字符串的起始位置,即src,然后赋给dest,接着让src向后移动,再给dest,这样依次让src往后移动,当然每次赋值完后相应的dest也要向后移动。
最优代码如下: ``` char *my_strcpy(char *dest, const char *src)//源字符串不能被改变 { assert(dest&&src);//保证两个指针的有效性 while (*dest++=*src++)//遇到'\0'停下来 { ;//先将src赋给dest,再让各自往后移动 } return dest; } ```

3.模拟实现strncpy函数

strncpy函数是将源字符串拷贝到目标字符串里 ,相比strcpy多了一个参数,拷贝个数有限制
char *my_strncpy(char *dest, char *src, size_t num)
{
	char *p = dest;
	assert(dest&&src);
	while (num--&&*src)
	{
		*dest++ = *src++;
		
	}
	if (num > 0)
	{
		num = num + 1;
		while (num--)
		{
			*dest++ = '\0';	//当src的大小小于num时,补'\0',直到补到num

		}
	}
	return p;
}

4.模拟实现strcat函数

strcat函数是将源字符串连接在目标字符串后面
思路:首先我们需要找到目标字符串’\0‘前面的位置,其次找到目标字符串的首位置,最后将两个字符串连接
char *my_strcat(char *dest, const char*src)//源字符串不能被改变
{
	assert(dest&&src);//指针不为空
	while(*dest)
	{
		dest++;//找到目标字符串的最后一个位置
	}
	while(*dest++ = *src++)//
	{
		;//将目标字符串接在源字符串后面,源字符串和目标字符串分别向后移
	}
	return dest;返回目标字符串首地址
}

5.模拟实现strncat函数

strncat函数是将源字符串连接在目标字符串后面 ,它相比strcat多了一个参数,是限制连接的个数
思路:首先我们需要找到目标字符串’\0‘前面的位置,其次找到目标字符串的首位置,最后将两个字符串连接,连接完之后会在后面加上‘\0’
char *my_strncat(char *dest,const char *src, size_t num)
{
	char *p = dest;
	assert(dest&&src);
	while (*dest)
	{
		dest++;
	}
	while (num--)
	{//要连接的个数作为循环条件
		*dest++ = *src++;
	}
	*dest = '\0';//最后加上'\0'
	return p;
}

6.模拟实现strstr函数

strstr是在源字符串里查找子字符串
思路:首先我们应该让子字符串先不动,在源字符串里从前往后遍历找到和子字符串首元素相同的元素,然后让各自都向后移动在进行比较,若后面后不同,则将源字符串移到下一个和子字符串首元素相同的元素,再进行比较,直到找到相同的,若找到,则返回子字符串所在元字符串中的位置及源字符串后面的部分,若找不到则返回空指针。
代码如下:
char *my_strstr(const char *src, const char *subsrc)//保证源字符串和子字符串不能被改变
{
	assert(src&&subsrc);//指针不为空
	const char *cur = src;//先将源字符串首位置存起来
	const char *s1 = cur;
	const char *s2 = subsrc;
	if (*subsrc == '\0')//如果子字符串为空,则不查找
		return (char *)src;
	while (*cur)
	{
		s1 = cur;
		s2 = subsrc;
		while (*s1&&*s2&&*s1==*s2)//两个相等,则各自向后移动,比较下一对是否相等
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return (char *)cur;
		cur++;//若没找到,源字符串向后移动
	}
	return NULL;
}

7.模拟实现strcmp函数

strcmp比较两个字符串的大小
思路:两个字符串从前向后依次比较,若ASCLL值相等,则继续向后比较,结果返回两个字符串的差值,即前大于后,返回正数,前等于后返回0,前小于后返回负数。
int my_strcmp(const char *s1, const char *s2)//两个字符串不能被改变
{
	assert(s1&&s2);//指针不能为空
	while (*s1 == *s2)
	{
		if (*s1 == '\0')
			return 0;
		s1++;//如果相等继续向后比较
		s2++;
	}
	return *s1 - *s2;//返回差值
}

8.模拟实现strncmp函数

strncmp比较两个字符串的大小,相比strcmp有比较个数的限制,前大于后返回1,前等于后返回0,前小于后,返回-1。
``` int my_strncmp(const char *dest,const char *src, size_t num) { assert(dest&&src); while ((num--) && (*dest == *src)) { dest++; src++; } if ((*dest - *src) > 0) return 1; else if ((*dest - *src) < 0) return -1; else return 0; } ```

9.模拟实现memcpy函数

memcpy是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
思路:整体和strcpy思路相差无几,但是要注意的是strcpy只是拷贝字符串,而memcpy可以拷贝任意类型。
代码如下:
void* my_memcpy(void *dest, const void *src, size_t count)//count是指要拷贝的字节数
{//返回值、参数可以是任意类型
	void *ret = dest;
	assert(dest&&src);//指针不为空
	while (count--)
	{
		*(char *)dest = *(char *)src;//这里要先转化成char*类型才可以进行运算,因为参数是void*类型
		dest = (char *)dest + 1;//因为++的运算级别高,所以向后移动的时候不能直接写++
		src = (char *)src + 1;
	}
	return ret;
}

注:source和destin所指的内存区域可能重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前不被覆盖。
##10.模拟实现memmov函数

memmove用于从src拷贝count个字节到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。
思路:memmov在memcpy的基础上更高了一级,因为memmov可以实现由重叠现象的内存拷贝
代码如下:
void *my_memmov(void *dest, const void *src, size_t count)//count表示要移动的字节数
{//返回值和参数类型可以是任意类型
	void *ret = dest;//将目标字符串首地址存起来
		assert(dest&&src);//指针不能为空
		if (dest < src)//当目标字符串在源字符串的前面时,从前向后拷贝
		{
			while (count--)
			{
				*(char *)dest = *(char *)src;//这里依然是转化成char*类型才可以进行计算
				dest = (char *)dest + 1;
				src = (char *)src + 1;
			}
		}
		else//如果目标字符串在源字符串首地址的后面,从后向前拷贝
		{
			src = (char *)src + count - 1;
			dest = (char *)dest + count - 1;
			while (count--)
			{
				*(char *)dest = *(char *)src;//这里依然是转化成char*类型才可以进行计算
				dest = (char *)dest - 1;
				src = (char *)src - 1;
			}
		}
		return ret;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值