库函数详解(二)—— 内存函数+模拟实现(部分)

文章目录

  • memcpy——内存拷贝1
    • 1.函数功能
    • 2.模拟实现
  • memmove——内存拷贝2(可重叠)
    • 1.函数功能
    • 2.模拟实现
  • memcmp——内存比较
  • memset——内存设置

memcpy——内存拷贝1

1.函数功能

库函数详解(二)—— 内存函数+模拟实现(部分)_第1张图片
memcpy函数是用于拷贝内存块的函数,该函数有三个参数,第一个参数为拷贝的目标地址(void * destination),第二个参数为拷贝源地址(const void * source),因为在拷贝过程中源字符串不会变化,所以参数用 const 修饰,第三个参数为在内存中拷贝的字节数(size_t num),该参数决定了拷贝内存的大小。返回值为拷贝目标的的首地址,因为不清楚拷贝数据的类型,所以返回类型为 void* 型。

对于该函数,要注意:
1.函数memcpy从 source 的位置开始向后复制 num 个字节的数据到destination的内存位置。
2.这个函数在遇到 ‘\0’ 的时候并不会停下来。
3.如果source和destination有任何的重叠,复制的结果都是未定义的(为拷贝的内容会被覆盖)。

举个栗子:
库函数详解(二)—— 内存函数+模拟实现(部分)_第2张图片

2.模拟实现

#include
#include
#include
void* my_memcpy(void* dest, const void* src, size_t num)
{
    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[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 20);
	return 0;
}

memmove——内存拷贝2(可重叠)

1.函数功能

库函数详解(二)—— 内存函数+模拟实现(部分)_第3张图片
该函数的参数的意义与返回类型同memcpy一样,但是该函数的功能与memcpy略有区别,区别在于:
memmove函数的源内存块和目标内存块是可以重叠的,而memcpy函数的源内存块和目标内存块是不可以重叠的。
所以在拷贝中如果源空间和目标空间出现重叠,就得使用memmove函数处理。

例如:
库函数详解(二)—— 内存函数+模拟实现(部分)_第4张图片
可以看出,在上述代码中,第一次使用memmove函数时,arr1 < arr+3 ,且拷贝的内存的大小为20字节(即5个整型),即将arr1中的"4 5 6 7 8"序列拷贝到" 1 2 3 4 5"的位置上,两序列有重叠的部分,所以为了拷贝成功,函数是将序列"4 5 6 7 8" 中的内存(每个字节)依次从前向后拷贝(若从后向前拷贝,则原本待拷贝的内容将会被首先拷贝的内容覆盖,从而造成拷贝的序列出错),所以拷贝的过程如下图所示:
库函数详解(二)—— 内存函数+模拟实现(部分)_第5张图片
而在第二次使用memmove函数时,arr2+2 > arr2,拷贝的内存大小为20字节,为了保证拷贝过程中的合理,第二次拷贝时内存中的序列时从后向前拷贝,如下:
库函数详解(二)—— 内存函数+模拟实现(部分)_第6张图片

所以从以上两次的拷贝结果可以看出memmove的拷贝机制为:
库函数详解(二)—— 内存函数+模拟实现(部分)_第7张图片
当 dest < src 时,src 指向的内容拷贝的方式为从前向后拷贝
当 dest > src 时,src 指向的内容拷贝的方式为从后向前拷贝(如上图)

2.模拟实现

根据拷贝机制我们可以模拟实现该函数:

#include
#include
#include
void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);//断言
	void* ret = dest;//保存待返回的首地址
	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;
}

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1+3, arr1, 20);
	return 0;
}

memcmp——内存比较

函数功能:
在这里插入图片描述
该函数用来比较两个内存块大小的函数,函数有三个参数,ptr1,ptr2分别为两个待比较的内容的首地址,因为不清楚待比较是内容是什么类型,所以两指针的类型被定义为void* 型,第三个参数为待比较的内存大小(单位字节);与strcmp函数的比较方式类似,但比较的内容不同,该函数会比较从ptr1和ptr2指针开始的num个字节,当ptr1大于ptr2的时候返回一个大于0的数;当prt1等于ptr2的时候返回0;当ptr1小于ptr2的时候返回一个小于0的数。
栗子如下:

#include
#include
int main()
{
	int arr1[] = { 1, 2, 3, 4 };
	int arr2[] = { 1, 2, 4, 5 };
	int ret1 = memcmp(arr1, arr2, 8);
	int ret2 = memcmp(arr1, arr2, 9);
	printf("%d  %d", ret1, ret2);
	return 0;
}

在这里插入图片描述
因为arr1,与arr2 在内存中的存储的内存如下图,因为前8个字节的内容相同,所以ret1=0,而第9个字节中的内容不同,所以ret2=-1。
库函数详解(二)—— 内存函数+模拟实现(部分)_第8张图片

memset——内存设置

函数功能:
在这里插入图片描述
该函数是将内存块中的某一部分设置为特定的字符;函数有三个参数,第一个参数是开始设置内存的起始位置,第二个参数是内存将要被设计成的特定字符,第三个参数是从起始位置开始需要设置的内存的字节数。
需要注意的是,该函数设置内存时是一个字节一个字节地进行设置。
举个例子:
库函数详解(二)—— 内存函数+模拟实现(部分)_第9张图片
再例如:
将字符串 “Hello world!” ,变为 “##### world!” ,代码如下:

#include
#include
int main()
{
	char str[] = "Hello world!";
	char* ret = memset(str, '#', 5);//字符‘#’传入函数内存的为相应的ASCII值,
	                                //设置的内存大小为5个字节
	printf("%s\n", ret);
	return 0;
}

在这里插入图片描述

你可能感兴趣的:(C语言,库函数)