常见内存函数的讲解及模拟实现——C语言

目录

一、内存函数

二、memcpy

2.1 memcpy的介绍及使用    

 2.2memcpy函数的模拟实现

三、memmove

3.1 memmove的介绍及使用

 3.2 memmove函数的模拟实现

四、memcmp

4.1memcmp的介绍及使用

 4.2 memcmp函数的模拟实现

五、memset

5.1 memset的介绍及使用

​5.2 memset函数的模拟实现


一、内存函数

        内存函数与字符串函数大有区别,首先字符串函数仅限于字符串之间的使用,而内存函数可以对任意类型使用,因为不管你传入什么类型的数组,它都是用void*来接收,其次字符串函数关注字符串后面的'\0',而内存函数不关注末尾的'\0',只关注要拷贝或者传入的字节数。

        常见内存函数有memcpy/memmove/memcmp/memset   下面就由小编带着大家对这些内存函数做更深入的了解,以及模拟实现吧!

二、memcpy

2.1 memcpy的介绍及使用    

         参数介绍:在库函数中,memcpy的参数有三个,分别是目标数组的地址,源数组的地址(被拷贝数组),这两个参数都是使用void*类型的指针来接收,因为void* 的指针可以接收任何类型的指针。最后一个参数就是要操作的字节数,或者说要访问的字节数。该函数的返回值是一个void*的指针,指向目标数组的首地址。

        功能介绍:该函数要实现从src这个位置开始,向后复制count个字节大小的数据到dest的内存位置中去,该函数遇到'\0'并不会停下来。

        代码使用:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 20);//从arr1中拷贝20个字节大小的数据到arr2中
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

 

 2.2memcpy函数的模拟实现

        注意:①因为源数组(被拷贝的数组)不能改变,所以我们用const修饰,起保护作用                         ②void 类型不能直进行解引用操作或者++运算,所以在使用之前我们需要进行强制类型转换,又因为这里我们是逐字节操作,所以我们需要将这两个指针强制转换成char*类型来进行操作,这样就可以实现我们想要的效果

                   ③在拷贝过程中,我们的dest的指向会发生变化,所以在最开始,我们创建一个临时的指针变量来接收一下,方便最后返回

                    ④在刚进入函数的时候,我们需要用assert断言一下,防止传入的是空指针 

   具体代码如下:

        

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest,const void* src,size_t num)//源头数组不被改变,const修饰
                                                      //传过来的不会为负数,所以类型为size_t
{
	assert(dest && src);
	void* ret = dest;
	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 };
	my_memcpy(arr2, arr1, 20);
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

但是memcpy不支持自身内部拷贝,当我们对同一块空间(存在覆盖)的数组进行操作时,会达不到我们想要的结果。重叠的内村拷贝要使用memmove函数来实现。

三、memmove

3.1 memmove的介绍及使用

        memmove和memcpy的参数和返回值一模一样,所要达到的效果和memcpy也一模一样,它比meecpy要更好一下,相当于优化,也就是当目标空间和源空间出现重叠的时候,就需要memmove来实现。

        代码使用:

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	           //  1 2 1 2 3 4 5 8 9 10   
	memmove(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

 3.2 memmove函数的模拟实现

        memmove模拟实现的时候,我们应该注意,因为目标空间和源空间可能出现重叠的情况,所以我们要分情况来讨论,

情况一:dest<src的时候,我们需要从前向后拷贝

 情况二:dest>src的时候,我们需要从后向前拷贝

        

情况三:dest和src指向的数组无重叠的情况,从前向后以及从后向前都可以 

 如上三种情况我们可以简化为两种情况,如下图

 具体代码如下所示

        

void* my_memmove(void* dest, void* src, size_t num)
{
	//断言
	assert(dest && src);
	void* ret = dest;
	if (dest > src)//如果目标地址大于被拷贝(源头)地址,从后向前拷贝
	{
		while (num--)
		{
			*((char*)dest+num) = *((char*)src+num);
		}
	}
	else//如果目标地址小于等于被拷贝(源头)地址,从前向后拷贝
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	return ret;
}

四、memcmp

4.1memcmp的介绍及使用

 

        参数介绍:memcmp和memcpy的参数也是一样的,区别就是 返回值不一样,该函数返回值为int,具体如下图所示

 功能实现:比较两个内存块,将ptr1所指向的内存块的前num个字节与ptr2指向的前num字节数进行比较。(注意:是逐字节比较)

代码使用:

int main()
{
	int arr1[] = { 1,2,3,4 };
	int arr2[] = { 1,2,3,5 };
	int ret=memcmp(arr1, arr2,16);
	printf("%d", ret);
	return 0;
}

 

 4.2 memcmp函数的模拟实现

        具体代码如下:

int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
	//断言
	assert(ptr1 && ptr2);
	while (num--&&*(char*)ptr1==*(char*)ptr2)
	{
		ptr1 = (char*)ptr1 + 1;
		ptr2 = (char*)ptr2 + 1;
	}
	return (*(char*)ptr1-*(char*)ptr2);
}
int main()
{
	int arr1[] = { 1,2,3,4 };
	int arr2[] = { 1,2,3,5 };
	//int ret=memcmp(arr1, arr2,16);
	int ret = my_memcmp(arr1, arr2, 20);
	if (ret == 0)
		printf("等于\n");
	else if (ret < 0)
		printf("小于\n");
	else
		printf("等于\n");
	//printf("%d\n", ret);
	return 0;
}

五、memset

5.1 memset的介绍及使用

  参数介绍:第一个是void*的指针,第二个是int类型的,第三个是无符号类型的整数,返回值是void*类型

功能实现:填充内存块,也就是设置内存,也就是把dest指向的前count字节的内容,设置成'c'的值,注意:以字节为单位来设置,而不是个数。最后返回dest指向的空间地址

代码使用:

int main()
{
	char arr1[] = "hello csdn";
	memset(arr1+1, 'x', 4);//
	printf("%s\n", arr1);
	return 0;
}

5.2 memset函数的模拟实现

代码如下:

void* my_memset(void* dest, int c, size_t count)
{
	assert(dest);
	void* ret = dest;//记住初始位置
	while (count--)
	{
		*(char*)dest = c;  //赋值
		dest = (char*)dest + 1;  //向后移动
	}
	return ret;
}

        到这里,我们今天要介绍的几个常见的内存函数就介绍完了,小编这里建议你看完之后再去动手实际操作一下,搞清楚这些内存函数的原理。希望今天这篇文章对你起到一定的帮助。如果觉得小编写的还可以的,可以一键三连(点赞,关注,收藏)哦,你们的支持是对小编极大的鼓励。谢谢。

 

 

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

褪色~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值