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

news/2025/2/27 5:18:59

目录

一、内存函数的使用

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.niftyadmin.cn/n/5869485.html

相关文章

av_find_input_format 和 AVInputFormat 的关系

1. av_find_input_format 和 AVInputFormat 的关系 av_find_input_format 是 FFmpeg 中的一个函数&#xff0c;用于根据输入格式的名称&#xff08;如 "mp4"、"wav"、"avfoundation" 等&#xff09;查找对应的输入格式结构体 AVInputFormat。 …

Python学习第十七天之PyTorch保姆级安装

PyTorch安装与部署 一、准备工作二、pytorch介绍三、CPU版本pytorch安装1. 创建虚拟环境2. 删除虚拟环境1. 通过环境名称删除2. 通过环境路径删除 3. 配置镜像源4. 安装pytorch1. 首先激活环境变量2. 进入pytorch官网&#xff0c;找到安装指令 5. 验证pytorch是否安装成功 四、…

PyCharm社区版如何运行Django工程?

PyCharm 社区版虽然不像专业版那样提供对 Django 的直接支持&#xff0c;但仍然可以通过一些手动配置来运行 Django 工程。以下是详细的步骤&#xff1a; 步骤 1&#xff1a;安装 Django 确保你的环境中已经安装了 Django。如果没有安装&#xff0c;可以通过以下命令安装&…

NLP09-朴素贝叶斯问句分类(3/3)

首先有个问句分类类&#xff1a; class QuestionClassify: 以下均为该类中的属性。 def __init__(self):self.train_x Noneself.train_y Noneself.tfidf_vec Noneself.train_vec Noneself.model Noneself.question_category_dict None__init__ 是 Python 中的一个特殊方…

C++ ⾼性能内存池

目录 项⽬介绍 小知识点补充 定位new 英语单词&#xff1a; 什么是内存池 1.池化技术 2.内存池 3.内存池主要解决的问题 3.1 效率问题 3.2 碎片化 3.2.1 外碎片 4.了解一下malloc 先设计⼀个定⻓的内存池 New的实现 Delete的实现 性能测试 脱离malloc直接在…

「软件设计模式」命令模式(Command)

揭秘命令模式&#xff1a;用C实现智能家居的"万能遥控器" 一、从餐厅点餐看命令模式精髓 想象你坐在餐厅点餐时&#xff0c;服务员记录你的订单交给后厨&#xff0c;这个看似简单的过程蕴含着软件设计的智慧。命令模式&#xff08;Command&#xff09;正是将这种&quo…

超大规模分类(四):Partial FC

人脸识别任务里&#xff0c;通常利用全连接层&#xff0c;来做人脸的分类。会面临三个实际问题&#xff1a; 真实的人脸识别数据噪声严重真实的人脸识别数据存在严重的长尾分布问题&#xff0c;一些类别样本多&#xff0c;多数类别样本少人脸类别越来越多&#xff0c;全连接层…

Nacos + Dubbo3 实现微服务的Rpc调用

文章目录 概念整理基本概念概念助记前提RPC与HTTP类比RPC接口类的一些理解 实例代码主体结构父项目公共接口项目提供者项目项目结构POM文件实现配置文件实现公共接口实现程序入口配置启动项目检查是否可以注入到Nacos 消费者项目项目结构POM文件实现配置文件实现注册RPC服务类实…