C语言中的内存函数使用与模拟实现

目录

一、内存函数的使用

1、memcpy()函数

2、memmove()函数

3、memcpy()函数

4、memset()函数:

二、内存函数的模拟实现

1、模拟实现memcpy()函数

2、模拟实现memmove()函数


一、内存函数的使用

1、memcpy()函数

memcpy()函数可以指定字节数,把源空间的内容拷贝到目的空间中 ,第一个参数是目的空间,第二个参数是源空间,第三个参数是指定的字节数,该函数的参数和返回值均为void*,可以接收任意类型数据的地址,该函数返回值是目标空间的起始地址。

cpp 复制代码
//memcpy()函数
int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int arr1[10] = { 0 };
	//想要把arr中的20个字节的数据拷贝到arr1中
	memcpy(arr1, arr, 20);
	for (int i = 0; i < 10; i++)
		printf("%d ", arr1[i]);
	printf("\n");

	float arr2[10] = { 3.14f, 2.13f, 9.16f, 7.98f, 6.07f, 0.29f };
	float arr3[10] = { 7.98f, 6.07f, 0.29f };
	memcpy(arr2, arr3, 20);
	for (int i = 0; i < 10; i++)
		printf("%lf ", arr2[i]);
	return 0;
}

注意:该函数拷贝同样要满足目标空间足够大,拷贝的字节数也不能乱指定。

2、memmove()函数

cpp 复制代码
//memmove()函数
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	memmove(arr + 2, arr, 20);
	for (int i = 0; i < 10; i++)
		printf("%d ", arr[i]);//打印结果为:1 2 1 2 3 4 5 8 9 10
	return 0;
}

memmove()函数的功能与memcpy()函数大致相同,只不过一个是可以原地拷贝,另一个是异地拷贝。

3、memcpy()函数

memcmp()函数是比较内存中指定字节内的数据。

cpp 复制代码
//memcmp()函数
int main()
{
	int arr1[10] = { 1, 2, 3, 4, 5 };
	int arr2[10] = { 2, 4, 6, 8, 10 };
	int arr3[10] = { 1, 2, 3, 4, 1 };
	int arr4[10] = { 1, 2, 3, 4, 5 };
	printf("%d\n", memcmp(arr1, arr2, 12));//打印结果为:-1
	printf("%d\n", memcmp(arr1, arr3, 20));//打印结果为:1
	printf("%d\n", memcmp(arr1, arr4, 20));//打印结果为:0
	//该函数的返回值与strcmp相同,如果前者小于后者,返回负数,否则返回正数,相等返回0
	return 0;
}

4、memset()函数:

cpp 复制代码
//memset()函数
int main()
{
	char str[] = "hello world!";
	memset(str, 'x', 5);//将字符串str的前5个字节设置为'x'
	printf("%s\n", str);//打印结果为:xxxxx world!
	return 0;
}

**memset()函数可以指定字节数来设置内存,设置的值可以自己指定。**使用该函数时,不能设置常量字符串,另外指定的是字节数,不是元素个数。

cpp 复制代码
//memset()函数
int main()
{
	int arr[10] = { 0 };
	memset(arr, 1, sizeof(arr));
	for (int i = 0; i < 10; i++)
		printf("%x\n", arr[i]);
	return 0;
}

上面代码中,将arr数组中的元素的每一个字节都设置成了1。

二、内存函数的模拟实现

1、模拟实现memcpy()函数

cpp 复制代码
//模拟实现memcpy()函数
void* my_memcpy(void* dest, const void* src, size_t size)
{
	assert(dest && src);
	void* ret = dest;
	while (size--)
	{
		//void*指针不能直接解引用和加减运算
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;//这样写比((char*)dest)++更加稳定
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr[10] = { 1, 2, 3, 4, 5 };
	int arr1[10] = { 10, 20, 30 };
	my_memcpy(arr, arr1, 12);
	for (int i = 0; i < 10; i++)
		printf("%d ", arr[i]);//打印结果为:10 20 30 4 5 0 0 0 0 0
	return 0;
}

下面演示自己设计的memcpy()函数在同一块空间的拷贝情况。

cpp 复制代码
//模拟实现memcpy()函数在同一块空间拷贝
void* my_memcpy(void* dest, const void* src, size_t size)
{
	assert(dest && src);
	void* ret = dest;
	while (size--)
	{
		//void*指针不能直接解引用和加减运算
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;//这样写比((char*)dest)++更加稳定
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	my_memcpy(arr + 2, arr, 20);//期望结果1 2 1 2 3 4 5 8 9 10
	for (int i = 0; i < 10; i++)
		printf("%d ", arr[i]);//打印结果为:1 2 1 2 1 2 1 8 9 10
	//出现这种原因的情况是因为内存重叠时候,使用memcpy()函数可能会出问题
	//那么如果在同一空间下拷贝,通常使用memmove()函数
	return 0;
}

C语言的memcpy()函数主要拷贝不重叠的内存,重叠的内存由memmove()函数拷贝,虽然在VS编译器上使用memcpy()函数可能也能拷贝内存重叠的情况,这是因为VS编译器对memcpy()函数功能实现与memmove()函数相同,但不是所有的编译器都这样。

2、模拟实现memmove()函数

cpp 复制代码
//模拟实现memmove()函数
void* my_memmove(void* dest, const void* src, size_t size)
{
	//使用memcpy()函数出现了内存覆盖,是因为将内存前面的数据拷贝到后面时,运用了从前向后拷贝
	//所以在实现memmove()函数时,如果将内存前面数据拷贝到后面,应该从后向前拷贝
	//如果是将内存后面数据拷贝到前面,应该从前向后拷贝,这就分成两种情况讨论
	//也就是dest<src时候,从前向后拷贝,dest>src时候,从后向前拷贝
	assert(dest && src);
	void* ret = dest;
	if (dest < src)//从前向后拷贝
	{
		while (size--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else//从后向前拷贝
	{
		while (size --)
			*((char*)dest + size) = *((char*)src + size);
	}
	return ret;
}

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	my_memmove(arr + 2, arr, 20);
	for (int i = 0; i < 10; i++)
		printf("%d ", arr[i]);//打印结果为:1 2 1 2 3 4 5 8 9 10
	return 0;
}
相关推荐
能来帮帮蒟蒻吗16 分钟前
Go语言学习(15)结构体标签与反射机制
开发语言·笔记·学习·golang
陈皮话梅糖@2 小时前
使用 Provider 和 GetX 实现 Flutter 局部刷新的几个示例
开发语言·javascript·flutter
hvinsion3 小时前
基于PyQt5的自动化任务管理软件:高效、智能的任务调度与执行管理
开发语言·python·自动化·自动化任务管理
Aphelios3803 小时前
Java全栈面试宝典:线程机制与Spring IOC容器深度解析
java·开发语言·jvm·学习·rbac
qq_529835354 小时前
装饰器模式:如何用Java打扮一个对象?
java·开发语言·装饰器模式
日暮南城故里4 小时前
Java学习------源码解析之StringBuilder
java·开发语言·学习·源码
Vitalia4 小时前
从零开始学Rust:枚举(enum)与模式匹配核心机制
开发语言·后端·rust
双叶8365 小时前
(C语言)虚数运算(结构体教程)(指针解法)(C语言教程)
c语言·开发语言·数据结构·c++·算法·microsoft
一个public的class6 小时前
什么是 Java 泛型
java·开发语言·后端
士别三日&&当刮目相看6 小时前
JAVA学习*Object类
java·开发语言·学习