系统性学习C语言-第十八讲-C语言内存函数

发布于:2025-07-17 ⋅ 阅读:(24) ⋅ 点赞:(0)

1. memcpy 使用和模拟实现

在这里插入图片描述

void * memcpy ( void * destination, const void * source, size_t num );

memcpy 函数,又称内存拷贝函数,将源数组中的内容拷贝到目标数组中,无论数组的类型,均能进行拷贝操作。

num 为要拷贝的字节数。

下面是使用 memcpy 函数的一些注意事项:

  1. 函数 memcpysource 的位置开始向后复制 num 个字节的数据到 destination 指向的内存位置。

  2. 这个函数在遇到 '\0' 的时候并不会停下来。

  3. 如果 sourcedestination 有任何的重叠,复制的结果都是未定义的。

函数使用举例:

#include <stdio.h>
#include <string.h>
int main()
{
 	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
 	int arr2[10] = { 0 };
 	memcpy(arr2, arr1, 20);
 	int i = 0;
 	for (i = 0; i < 10; i++)
 	{
 		printf("%d ", arr2[i]);
 	}
 	return 0;
}

对于重叠的内存,交给 memmove 函数来处理。

memcpy 函数的模拟实现:

void * memcpy ( void * dst, const void * src, size_t count)
{
 	void * ret = dst;
 	assert(dst);
 	assert(src);
 	while (count--) 
 	{
 		*(char *)dst = *(char *)src;
 		dst = (char *)dst + 1;
 		src = (char *)src + 1;
 	}
 	return(ret);
}

在对 memcpy 函数的模拟实现中,要解决的其中一个难点就是如何将不同类型的数组,用一样的代码来处理,

首先就要从参数部分下手,参数部分我们要将指针的类型设置成 void* ,这样所有类型的数组我们都能进行接收,

接下来就是处理数组的拷贝问题,void* 的指针是不能直接进行解引用的,这意味着我们必须要转换指针类型,

这时我们的参数还有字节数,这就说明在我们将 void* 指针类型强转为 char* 后,可以根据传入的字节数大小去兼职循环的次数。

所以对于拷贝的操作我们只需将指针强转,然后解引用赋值即可,但是我们仍然要解决指针的移动问题,

void* 类型的指针是不能进行自增的,所以这也意味着我们要进行强转,但是 *(char *)dst++ 强转后的自增是不可以的,

这样的代码相当于没有强转,所以我们只能采用强转赋值的方法去进行处理, dst = (char *)dst + 1; ,这样模拟实现的难点就都解决了。

2. memmove 使用和模拟实现

在这里插入图片描述

void * memmove ( void * destination, const void * source, size_t num );

memmove 内存移动函数,用于将源数组的内容拷贝放到目标数组中,与 memcopy 函数不同的是,

在 C语言 规定中 memmove 函数可以处理内存重叠部分的内容移动。

下面是使用 memmove 函数的一些注意事项:

  1. memcpy 的差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的。

  2. 如果源空间和目标空间出现重叠,就得使用 memmove 函数处理。

函数使用示例:

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

memmove 的模拟实现:

void * memmove ( void * dst, const void * src, size_t count)
{
 	void * ret = dst;
 	if (dst <= src || (char *)dst >= ((char *)src + count)) {
 	/*
 	* Non-Overlapping Buffers
 	* copy from lower addresses to higher addresses
 	*/
 		while (count--) 
 		{
 			*(char *)dst = *(char *)src;
 			dst = (char *)dst + 1;
 			src = (char *)src + 1;
 		}
 	}
 	else {
 	/*
 	* Overlapping Buffers
 	* copy from higher addresses to lower addresses
 	*/
 		dst = (char *)dst + count - 1;
 		src = (char *)src + count - 1;
 		while (count--) 
 		{
 			*(char *)dst = *(char *)src;
 			dst = (char *)dst - 1;
 			src = (char *)src - 1;
 		}
 	}
 return(ret);
}

对于 memmove 函数的模拟实现,难点在于我们如何处理重叠区域的内存移动,

我们先来分析在不同的情况下,重叠区域应该如何来移动:

在这里插入图片描述
在源数组与目标数组重叠部分在元素组偏后的元素时,我们如果先将源数组的内容从前往后放置到目标数组中,当 2 覆盖 5 后,

我们如果要将源数组的 5 覆盖目标数组的 8 时,我们就会发现此时 5 已经变成 2 ,无法达到我们的我目的,

所以我们要将源数组的内容从后往前放置到目标数组中,先将重叠区域的内容放置到目标数组中,避免被覆写后值改变。

所以目标数组与源数组重叠区域在源数组元素偏后时,我们就从后往前覆写。

在这里插入图片描述
跟上面一样进行分析后,当目标数组与源数组重叠区域在源数组元素偏前时,我们就从前往后覆写,避免重叠区域先被覆写。

当目标数组与源数组没有任何交集时,选择从前往后、从后往前的覆写方式均可以。这个难点被解决后,memmove 的模拟便再无难点

3. memset 函数的使用

在这里插入图片描述

void * memset ( void * ptr, int value, size_t num );

memset 是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。

函数使用示范:

#include <stdio.h>
#include <string.h>
int main ()
{
 	char str[] = "hello world";
 	memset (str,'x',6);
 	printf(str);
 	return 0;
}

对于 memset 函数在使用时我们一定要注意一点,对于这样的代码:

int arr[10] = {0};
memset (arr, 1, 4);

我们可千万不能认为是将 arr 数组的前四个元素置为 1 ,因为 memset 函数是以字节为单位进行设置,

所以是将 arr 数组的前四个字节全部置 1 ,也就是第一个元素的四个字节全部置 1,最后的结果为 16843099。

4. memcmp 函数的使用

在这里插入图片描述

int memcmp ( const void * ptr1, const void * ptr2, size_t num );
  1. 比较从 ptr1ptr2 指针指向的位置开始,向后的num个字节

  2. 返回值如下:
    在这里插入图片描述
    函数使用示例:

#include <stdio.h>
#include <string.h>
int main()
{
 	char buffer1[] = "DWgaOtP12df0";
 	char buffer2[] = "DWGAOTP12DF0";
 	int n;
 	n = memcmp(buffer1, buffer2, sizeof(buffer1));
	if (n > 0) 
 		printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
 	else if (n < 0) 
 		printf("'%s' is less than '%s'.\n", buffer1, buffer2);
 	else 
 		printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
 	return 0;
}

关于 memcpy 函数在使用时我们要注意下面的代码:

int arr[2] = {1, 2};
int arr1[3] = {1, 2, 3};
memcpy(arr, arr1, 9)

当函数比较第 9 个字节时,由于数组 arr 只开辟了 8 字节大小的空间,所以这时我们并不知道在数组 arr 后一个字节存储的内容,

这时系统仍然会根据内存中的内容进行比较,所以要避免写出这样的代码。


网站公告

今日签到

点亮在社区的每一天
去签到