内存操作函数(部分)

本文详细介绍了C语言中的memcpy和memmove函数,包括它们的用途、原型、注意事项以及如何模拟实现。重点在于处理重叠内存的情况,以确保正确复制数据并避免潜在问题。
摘要由CSDN通过智能技术生成

1,memcpy

1.1memcpy介绍和演示

memcpy 是 C 语言中的一个标准库函数,用于从源内存块复制指定数量的字节到目标内存块。这个函数的原型通常定义在 <string.h> 头文件中。
函数原型:

void *memcpy(void *dest, const void *src, size_t n);

参数一dest:指向目标内存块的指针,即要复制到的位置。
参数二src:指向源内存块的指针,即要复制的数据所在的位置。
参数三n:要复制的字节数。
返回值:返回指向目标内存块 dest 的指针。
memcpy是将内存逐个字节复制,操作对象是内存,所以两个参数都是用void*类型,可以接收任意类型的指针。
函数演示:

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest[20];
    memcpy(dest, src, 5); // 将 src 的前 5 个字节复制到 dest
    dest[5] = '\0'; // 确保字符串正确终止
    printf("Copied string: %s\n", dest); 
    return 0;
}

因为memcpy只会复制对应字节数的内存,所以我们还需自己增加一个’\0’确保字符串正常结尾。
结果为:
在这里插入图片描述
使用memcpy有几个注意事项,
一:memcpy 不会检查目标内存块是否足够大以容纳要复制的数据。如果目标内存块太小,会导致缓冲区溢出,
二:memcpy 不会检查源内存块和目标内存块是否重叠。如果两个内存块重叠,应使用 memmove 函数代替。

1.2memcpy模拟实现

因为memcpy函数的操作对象为内存块,所以memcpy应该对任意类型的数据都能进行复制,所以我们在模拟实现时要使用void*类型来接收参数,同时会返回一个指向目标内存的指针

#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest,const void* src,size_t num)
{
	void* ret = dest;//记录目标地址
	assert(dest && src);
	while (num--)
	{
		*(char*)dest = *(char*)src;
		((char*)dest)++;
		((char*)src)++;
	}//char*类型的指针解引用访问一个字节,逐个字节复制
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = {0};
	my_memcpy(arr2, arr1, 20);
	for (int i = 0;i < 10;i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

结果为
在这里插入图片描述

2,memmove

2.1memmove介绍和演示

在上面介绍memcpy函数时提到过,当复制的源内存块和目标内存块重叠时,不能使用memcpy,这时想正确地进行复制操作,应该使用另一个函数memmove。
memmove 是 C 语言中的一个标准库函数,用于从源内存块复制指定数量的字节到目标内存块,即使源内存块和目标内存块重叠,也能正确地进行复制操作。这个函数通常定义在 <string.h> 头文件中。
函数原型:

void *memmove(void *dest, const void *src, size_t n);

该函数的三个参数与返回值和memcpy没有区别,不同的是,在使用memmove进行复制内存时,函数会判断内存位置,然后正确的复制内存内容。
函数演示:

#include <stdio.h>
#include <string.h>
int main() 
{
    char str[] = "Hello, World!";
    memmove(str + 2, str, 5); 
    printf("Moved string: %s\n", str); 
    return 0;
}

结果为:
在这里插入图片描述

在这个示例中,memmove 函数将 str 的前 5 个字节(即 “Hello”)移动到了 str 的第 3 个位置开始处,因此字符串变为 “lllo, World!”。如果使用 memcpy 来完成这个操作,结果将是不确定的,因为源内存块和目标内存块重叠了。那memmove是如何完成复制的呢?我们分析可以得知,当我们从第一个字节开始逐个向后复制内存,复制了2个字节后字符串变为“HeHeo,World!”,此时在复制第三个字节的内存,字符串就将变为==“HeHeH,World!”==是错误的,这是因为前面的内容已经被覆盖了,
因此,当遇到这种情况时,我们可以选择从后向前复制,分析可得当复制2个字节内存后,字符串内容变为”Helloloorld!“,若从后向前复制,此时的src指针指向字符”l“,dest指针指向o,继续向后复制,能得到我们想要的结果。因此,memmve会跟据指针的位置判断是从前向后,还是从后向前复制内存。从而做到在复制的源内存块和目标内存块重叠时,正确的复制内存块。

2.2memmove模拟实现

综上所述,我们在模拟实现memmove函数时,最主要的就是理清,memmove函数什么时候从前向后复制内存块内容,什么时候从后向前复制内存块内容。我们可以画图方便理解:
在这里插入图片描述
经过分析,我们可以知道,当dest指针指向的地址在src指针指向的地址之前时,我们可以从前向后复制内存块,而当dest指针指向的地址在src指针指向的地址之后时,我们可以从后向前复制内存块。
也就是说,我们在模拟实现memmove函数时,得先判断两指针指向的地址大小。

#include<stdio.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	if (dest < src)//dest指针指向的地址在src指针指向的地址之前
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest =(char*)dest+1;
			src  =(char*)src+1;
		}
	}
	else//dest指针指向的地址在src指针指向的地址之后
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memmove(arr1+2, arr1, 5 * sizeof(int));
	for (int i = 0;i < 10;i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

两种结果
结果一:
在这里插入图片描述

结果二:
在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值