memcpy和memmove函数的介绍和模拟实现

news2024/11/20 7:11:47

注:这里给小伙伴们一些建议,看API文档的时候,一定要看全英,在本篇文章,我会带领大家看memcpy和memmove的全英解析,并翻译给大家。

目录

1. memcpy函数

1.1 函数的声明

1.2 函数的功能 

1.3 函数的使用

1.4 函数的模拟实现(重点)

1.4.1 模拟分析

1.4.1 模拟实现

2. memmove函数

2.1 函数的声明

2.2 函数的功能

2.3 函数的使用

2.4 函数的模拟实现(重点)

2.4.1 模拟分析

2.4.2 模拟实现

 


1. memcpy函数

1.1 函数的声明

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

  • destination

destination指向的是接收数据的目标,其类型转化为void*类型。

  • source

source指向提供数据复制的源头, 其类型转化为void*类型。

  • num

按字节为单位进行复制,size_t类型是无符号的整型类型

将destination指向的地址返回 

1.2 函数的功能 

  •  第一段

按字节为单位,从source位置开始将多少个字节数的数据复制给destination的内存块中。

  • 第二段

source和destination指针指向的底层数据类型和函数无关,结果是以二进制进行数据复制。

  • 第三段

函数不会检查是否有null或者'\0'在source中,它总是会准确复制num个字节数的数据。

  • 第四段

为了避免溢出,destination和source各自指向的数组大小至少是移动num个字节的大小,且不能出现destination和source指向的位置重叠(如果想要重叠,memmove是一个更安全的方法)。

1.3 函数的使用

/* memcpy example */
#include <stdio.h>
#include <string.h>
struct {
 char name[40];
 int age;
} person, person_copy;
int main ()
{
 char myname[] = "Pierre de Fermat";
 /* using memcpy to copy string: */
 memcpy ( person.name, myname, strlen(myname)+1 );
 person.age = 46;
 /* using memcpy to copy structure: */
 memcpy ( &person_copy, &person, sizeof(person) );
 printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );
 return 0;
}

1.4 函数的模拟实现(重点)

1.4.1 模拟分析

(1)首先,我们不知道要被复制的数据是什么类型,所以参数只能是void*来接收数据,既然不知道是什么数据类型,所以我们也不清楚指针要怎么跳跃去复制,所以只能一个一个字节去复制,这就必须在函数体内把destination和source指向强转成char*(这里就会有同学问了,为什么能直接用char*接收呢?答:因为char*只能接受char*的指针,而void*类型虽然不能直接访问,但是可以接收任何类型的指针)。且观察mencpy,发现需要一个目标指针destination、源头指针source和字节个数size_t  num。

(2)source指针指向的内容是不需要改变的,所以我们可以加上const修饰,把里面的数据保护起来(const void* source)。

(3)为了实现链式访问,我们要将传进来的目标起始地址(destination)返回。由于这个函数在执行的时候会改变destination存储的内容,所以我们要重新创建一个void*类型的指针来代替destination指针移动。

(4)为了避免传进来的地址是空指针,我们需要用assert来断言传进来的地址不是空指针。

1.4.1 模拟实现

//自我实现memcpy的功能
void* my_memcpy(void* destination, const void* source, size_t num) {
	//先判断destination和source是不是为空
	assert(destination && source);
	void* tmp = destination;
	while (num--) {
		//记住强转数据类型并不会永久改变变量的数据类型
		*(char*)tmp = *(char*)source;
		((char*)tmp)++;
		((char*)source)++;
	}
	return destination;
}

int main() {
	int a[4] = { 0 };
	int b[4] = { 1,2,3,4 };
	int num = sizeof(b);
	my_memcpy(a, b, num);
	for (int i = 0;i < 4;i++) {
		printf("%d ", a[i]);
	}
	return 0;
}

2. memmove函数

2.1 函数的声明

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

  • destination

destination指向的是接收数据的目标,其类型转化为void*类型。

  • source

source指向提供数据复制的源头, 其类型转化为void*类型。

  • num

按字节为单位进行复制,size_t类型是无符号的整型类型。

 将destination指向的地址返回 。

2.2 函数的功能

  • 第一段

按字节为单位,从source位置开始将多少个字节数的数据复制给destination的内存块中。复制就像使用了中间缓冲区一样,允许重叠复制。

  • 第二段

source和destination指针指向的底层数据类型和函数无关,结果是以二进制进行数据复制。

  • 第三段

函数不会检查是否有null或者'\0'在source中,它总是会准确复制num个字节数的数据。

  • 第四段

为了避免溢出,destination和source各自指向的数组大小至少是移动num个字节的大小。

2.3 函数的使用

/* memmove example */
#include <stdio.h>
#include <string.h>
int main()
{
	char str[] = "memmove can be very useful......";
	memmove(str + 20, str + 15, 11);
	puts(str);
	return 0;
}

2.4 函数的模拟实现(重点)

2.4.1 模拟分析

  • memcpy和memmove的比较

为什么需要memmove?就得了解memcpy和memmove的区别!

这个还要从上面的memcpy函数说起。因为memcpy函数不能将一个数组的中的数据拷贝到自身(也就是目标数据是自己,源数据也是自己,只不过是一个数组里面不同的位置的数据拷贝到另外一个位置上),如果像这样拷贝就会出现重叠拷贝,会导致结果不是我们预期的结果。

//使用我们自己的模拟的memcpy函数
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	my_memcpy(arr + 2, arr, 24);//预期出现结果为1 2 1 2 3 4 5 6 9 10
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);//实际出现结果
	}
	return 0;
}

  • 细节分析

2.4.2 模拟实现

//自我实现memmove的功能
void* my_memmove(void* destination, const void* source, size_t num) {
	//先判断destination和source是不是为空
	assert(destination && source);
	void* tmp = destination;
	//从前往后走
	if (destination < source) {
		while (num--) {
			*(char*)tmp = *(char*)source;
			((char*)tmp)++;
			((char*)source)++;
		}
	}
	//从后往前走
	else {
		while (num--) {
			*((char*)tmp + num) = *((char*)source + num);
		}
	}
	return destination;
}

int main() {
	int b[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(b, b + 3, 16);//b+3:是从4开始,预期结果:4,5,6,7,5,6,7,8,9,10
	for (int i = 0;i < 10;i++) {
		printf("%d ", b[i]);
	}
	printf("\n");
	int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(a+2, a, 24);//a+3:是从4开始,预期结果:1,2,3,1,2,3,4,8,9,10
	for (int i = 0;i < 10;i++) {
		printf("%d ", a[i]);
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1088638.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C/C++笔试易错题+图解知识点(二)—— C++部分

目录 1.构造函数初始化列表 1.1 构造函数初始化列表与函数体内初始化区别 1.2 必须在初始化列表初始化的成员 2. 引用初始化以后不能被改变&#xff0c;指针可以改变所指的对象 1.构造函数初始化列表 有一个类A&#xff0c;其数据成员如下&#xff1a; 则构造函数中&#xff0c…

2023年中国招投标行业研究报告

第一章行业概况 1.1 招投标定义 招标和投标&#xff0c;作为商品交易的关键环节&#xff0c;代表着一种高度成熟的商业实践&#xff0c;它涵盖了商品经济的多个层面&#xff0c;借助技术、经济学方法以及市场竞争机制&#xff0c;形成了有序而高效的交易方式。招标和投标是国…

分享一下开发回收废品小程序的步骤

随着人们环保意识的不断提高&#xff0c;回收利用已成为日常生活中不可或缺的一部分。回收小程序作为一种便捷、高效的回收方式&#xff0c;越来越受到人们的关注和喜爱。本文将探讨回收小程序的意义和作用&#xff0c;设计理念、功能特点、使用流程以及推广策略&#xff0c;并…

M2芯片的Mac上安装Linux虚拟机——提前帮你踩坑

M2芯片的Mac上安装Linux虚拟机——提前帮你踩坑 1. 前言1.1 系统说明1.2 Linux系统选择——提前避坑1.1 下载vmware_fusion1.1.1 官网下载1.1.2 注册 CAPTCHA验证码问题1.1.3 产品说明 1.2 下载操作系统镜像1.2.1 下载centos&#xff08;如果版本合适的&#xff09;1.2.2 下载…

C++下载器程序:如何使用cpprestsdk库下载www.ebay.com图片

本文介绍了如何使用C语言和cpprestsdk库编写一个下载器程序&#xff0c;该程序可以从www.ebay.com网站上下载图片&#xff0c;并保存到本地文件夹中。为了避免被网站屏蔽&#xff0c;我们使用了亿牛云爬虫代理服务提供的代理IP地址&#xff0c;以及多线程技术提高下载效率。 首…

02 | Spring Data Common 之 Repository 如何全面掌握?

通过上一课时&#xff0c;我们知道了 Spring Data 对整个数据操作做了很好的封装&#xff0c;其中 Spring Data Common 定义了很多公用的接口和一些相对数据操作的公共实现&#xff08;如分页排序、结果映射、Autiting 信息、事务等&#xff09;&#xff0c;而 Spring Data JPA…

mysql面试题46:MySQL中datetime和timestamp的区别

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:MySQL中DATETIME和TIMESTAMP的区别 在MySQL中,DATETIME和TIMESTAMP是两种用于存储日期和时间的数据类型。虽然它们都可以用于存储日期和时间信息…

Java版本+企业电子招投标系统源代码+支持二开+招投标系统+中小型企业采购供应商招投标平台

功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外部供…

大数计算:e^1000/300!

1.问题:大数计算可能超出数据类型范围 当单独计算 ,因为 e^{700} \approx 1.01432*e304" class="mathcode" src="https://latex.csdn.net/eq?e%5E%7B1000%7D%20%3E%20e%5E%7B700%7D%20%5Capprox%201.01432*e304">,double的最大取值为1.79769…

【NeRF】2、NeRF 首篇经典论文介绍(ECCV2020)

文章目录 一、背景二、方法2.1 神经辐射场场景表达3.2 使用辐射场来进行立体重建3.3 优化神经辐射场3.3.1 位置编码3.3.2 分层立体采样3.3.3 具体实现细节 三、效果 论文&#xff1a;Representing Scenes as Neural Radiance Fields for View Synthesis 代码&#xff1a;https…

攻防世界题目练习——Crypto密码新手+引导模式(二)(持续更新)

题目目录 1. 转轮机加密2. easychallenge 上一篇&#xff1a;攻防世界题目练习——Crypto密码新手引导模式&#xff08;一&#xff09;&#xff08;持续更新&#xff09; 1. 转轮机加密 首先了解一下轮转机加密吧。 传统密码学(三)——转轮密码机 题目内容如下&#xff1a; …

通讯录(C语言版)

用c语言实现一个通讯录 功能&#xff1a;.添加、删除、查找、更改、显示、排序联系人 内存存储方式&#xff1a;结构体数组 1.打印菜单&#xff0c;各个功能分别用函数实现&#xff0c;将函数声明放在头文件中。 2.定义联系人信息&#xff0c;将联系人信息与count&#xff…

云渲染是什么?云渲染怎么用?

云渲染的出现为影视动画、建筑设计、游戏开发等领域提供了很大的便利&#xff0c;为公司或者个人节约了大量的渲染部分时间&#xff0c;大大的提高了工作效率。哪什么是云渲染&#xff1f;云渲染怎么用呢&#xff1f;我们一起来看看。 云渲染是什么&#xff1f; 云渲染是一种…

高级深入--day30

Scrapy Shell Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据。 如果安装了 IPython ,Scrapy终端将使用 IPython (替代标准Python终端)。 IPython 终端与其…

QDir实践

现在有多个文件&#xff0c;路径为&#xff1a; a\xxx\kmd_config\c.json 其中xxx是变量 startcalc,,,,,, 目标&#xff1a; 访问每一个json文件 实例&#xff1a; QString app_path QApplication::applicationDirPath() "/app";QDir dir(app_path);QStringLi…

NewStarCTF2023公开赛道-压缩包们

题目提示是压缩包 用010editor打开&#xff0c;不见PK头&#xff0c;补上50 4B 03 04 14 00 00 00 将文件改成.zip后缀&#xff0c;打开&#xff0c;解压出flag.zip 尝试解压&#xff0c;报错 发现一串base64编码 SSBsaWtlIHNpeC1kaWdpdCBudW1iZXJzIGJlY2F1c2UgdGhleSBhcmUgd…

【LeetCode刷题笔记】二分查找

1539. 第 k 个缺失的正整数 解题思路&#xff1a; 1. 二分 &#xff0c;一个严格升序 正整数 数组在没有数字缺失的情况下满足&#xff1a; nums[i] i 1 &#xff0c;如果有缺失&#xff0c;则每个 下标 i 上的数字前面缺失的正整数个数为&#xff1a; nums[i] - (i 1) &am…

ROS 摄像头标定-camera_calibration

摄像头这种精密仪器对光学器件的要求较高&#xff0c;由于摄像头内部与外部的一些原因&#xff0c;生成的物体图像往往会发生畸变&#xff0c;为了避免数据源造成的误差&#xff0c;需要针对摄像头的参数进行标定。 ROS官方提供了用于双目和单目摄像头标定的功能包—camera_cal…

单链表---结构体实现

定义 链表称为线性表的链式存储&#xff0c;顺序表逻辑上相邻的数据&#xff0c;存储位置也相邻。链表逻辑上相邻的数据&#xff0c;存储位置是随机分布在内存的各个位置上的。 故 对于每一个结点&#xff0c;定义的结构体是&#xff1a; typedef struct _LinkNode {int d…

存档&改造【06】Apex-Fancy-Tree-Select花式树的使用误删页数据还原(根据时间节点导出导入)

之前一直想实现厂区-区域-产线之间的级联选取&#xff0c;于是导入插件Apex-Fancy-Tree-Select花式树 存档&#xff06;改造【03】Apex-Fancy-Tree-Select花式树的导入-CSDN博客 现在则是在Oracle Apex中的应用 花式书级联列表展示厂区-区域-产线 想要实现的效果 由厂区>…