当前位置: 首页 > article >正文

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

目录

一、内存函数的使用

1、memcpy()函数

2、memmove()函数

3、memcpy()函数

4、memset()函数:

二、内存函数的模拟实现

1、模拟实现memcpy()函数

2、模拟实现memmove()函数


一、内存函数的使用

1、memcpy()函数

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

//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()函数

//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()函数是比较内存中指定字节内的数据。

//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()函数:

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

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

//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()函数

//模拟实现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()函数在同一块空间的拷贝情况。

//模拟实现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()函数

//模拟实现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;
}


http://www.kler.cn/a/568019.html

相关文章:

  • Python面试(八股)
  • MyBatis-Plus 为简化开发而生【核心功能】
  • 【React】事件绑定的细节
  • 地基JDK8新特性之Lambda 表达式和Stream 流操作
  • 怎么进行mysql的优化?
  • 秒杀系统的常用架构是什么?怎么设计?
  • 实战-使用 Playbook 批量部署多台 LAMP 环境
  • 智能DNS是干嘛的?
  • 【音视频】 H264 H265
  • 从入门到精通:用VxeTable重构你的Ant Design表格
  • openssl下aes128算法CBC模式加解密运算实例
  • 什么是覆盖索引-MySql
  • Brave 132 编译指南 Android 篇 - 获取源代码 (四)
  • 大模型中的数据清洗:方法与实践
  • 深入解析Crawl4AI:为AI应用量身定制的高效开源爬虫框架
  • git:分支控制
  • C/C++动静态库的制作与原理 -- 静态库,动态库,目标文件,ELF文件,动态链接,静态链接
  • 微服务笔记 2025/2/15
  • weaviate 安装与测试
  • 医疗行业电脑终端如何防病毒——火绒企业版杀毒软件