C语言实现memcpy、memmove库函数

news2024/11/16 9:36:33

目录

  • 引言
  • 一、库函数介绍
  • 二、库函数详解
  • 三、源码实现
    • 1.memcpy源码实现
    • 2.memmove源码实现
  • 四、测试
    • 1.memcpy函数
    • 2.memmove函数
  • 五、源码
    • 1.memcpy源码
    • 2.memmove源码
  • 六、参考文献

引言

关于memcpy和memmove这两个函数,不论是算法竞赛还是找工作面试笔试,对这两个函数必然是经常都会用到,而且面试的时候很有可能会让你把代码复现出来,也许会问你这两个库函数的区别,这都是你自学才能知道的,所以也是很能体现你实力的一种,所以说很重要,话不多说了,那就开始介绍吧。


一、库函数介绍

#include <cstring>  // CPP版头文件
#include <string.h>  //C版头文件

void *memcpy(void *dest, const void *src, size_t count); 
void *memmove(void *dest, const void *src, size_t count); 

功能:把从src开始的n个字节拷贝到以dest开始的内存区域中,返回dest(可进行链式嵌套调用)
在这里插入图片描述

区别: memcpy要求在使用时这两块区域不能有重叠,也就是不能出现自拷贝的情况,而memmove则保证在有重叠的情况下,结果是正确的。


二、库函数详解

memcpy:强转为char*,解引用从前到后依次赋值count次。

但是遇到如下图的情况:在src赋值的同时会把自己原本的值给覆盖掉,就会出现与使用者本意不相符的情况发生,所以memcpy不允许这两块区域重叠。
在这里插入图片描述

但如果是如下图这种情况:dest会跟本意一样,只不过src有些变了,但目的还是dest所以这个是没关系的,所以这种情况不考虑,因为设计者也是这么写的。
在这里插入图片描述

memmove:遇到有可能发生重叠的情况,从后往前赋值,就不会出错了,可以看图想想。
在这里插入图片描述


三、源码实现


这里值得注意的就是*d++这块,++优先级高,所以先d++,结果为d,然后*d,语句结束后d才++。

1.memcpy源码实现

void* memcpy(void* dest, const void* src, size_t count)
{
	if (dest == NULL || src == NULL || count == 0) return dest;

	char* d = (char*)dest;
	char* s = (char*)src;

	while (count--)
	{
		*d++ = *s++;
	}

	return dest;
}

2.memmove源码实现

void* memmove(void* dest, const void* src, size_t count)
{
	if (dest == NULL || src == NULL || count == 0) return dest;

	char* d = (char*)dest;
	char* s = (char*)src;

	if (dest < src)
	{
		while (count--)
		{
			*d++ = *s++;
		}
	}
	else
	{
		d += count;
		s += count;

		while (count--)  // 从后往前赋值
		{
			*--d = *--s;  // 注意这里先减减
		}
	}
	
	return dest;
}

四、测试

1.memcpy函数

int main()
{
	const size_t size = 20;
	int a[size] = { 0,1,2,3,4,5,6,7,8,9 };
	int b[size];

	memcpy(b, a, 10 * sizeof(int));  //注意这里是字节数
	for (int i = 0; i < size; ++i) printf("%d ", b[i]);

	return 0;
}

在这里插入图片描述


可以看出如下的例子:说明memcpy不能自拷贝

int main()
{
	const size_t size = 20;
	int a[size] = { 0,1,2,3,4,5,6,7,8,9 };
	int b[size];

	memcpy(a+4, a, 10 * sizeof(int));  //注意这里是字节数
	for (int i = 0; i < size; ++i) printf("%d ", a[i]);

	return 0;
}

在这里插入图片描述

2.memmove函数


如下例子可以看出与memcpy的区别

int main()
{
	const size_t size = 20;
	int a[size] = { 0,1,2,3,4,5,6,7,8,9 };
	int b[size];

	memmove(a+4, a, 10 * sizeof(int));  //自拷贝
	for (int i = 0; i < size; ++i) printf("%d ", a[i]);

	return 0;
}

在这里插入图片描述

正常例子:

int main()
{
	const size_t size = 20;
	int a[size] = { 0,1,2,3,4,5,6,7,8,9 };
	int b[size] = {0};

	memmove(b, a, 10 * sizeof(int));  //注意这里是字节数
	for (int i = 0; i < size; ++i) printf("%d ", b[i]);

	return 0;
}

在这里插入图片描述


五、源码

1.memcpy源码

/***
*memcpy.c - contains memcpy routine
 
*Purpose:
*       memcpy() copies a source memory buffer to a destination buffer.
*       Overlapping buffers are not treated specially, so propogation may occur.
*
 **********/

#include <cruntime.h>
#include <string.h>

#pragma function(memcpy)

/***
*memcpy - Copy source buffer to destination buffer
*
*Purpose:
*       memcpy() copies a source memory buffer to a destination memory buffer.
*       This routine does NOT recognize overlapping buffers, and thus can lead
*       to propogation.
*
*       For cases where propogation must be avoided, memmove() must be used.
*
*Entry:
*       void *dst = pointer to destination buffer
*       const void *src = pointer to source buffer
*       size_t count = number of bytes to copy
*
*Exit:
*       Returns a pointer to the destination buffer
*
*Exceptions:
*******************************************************************************/

void * __cdecl memcpy (
        void * dst,
        const void * src,
        size_t count
        )
{
        void * ret = dst;

#if defined (_M_IA64)

        {


        __declspec(dllimport)


        void RtlCopyMemory( void *, const void *, size_t count );

        RtlCopyMemory( dst, src, count );

        }

#else  /* defined (_M_IA64) */
        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
        }
#endif  /* defined (_M_IA64) */

        return(ret);
}

2.memmove源码

/***
*memmove - Copy source buffer to destination buffer
*
*Purpose:
*       memmove() copies a source memory buffer to a destination memory buffer.
*       This routine recognize overlapping buffers to avoid propogation.
*       For cases where propogation is not a problem, memcpy() can be used.
*
*   Algorithm:
*******************************************************************************/

void* memmove(void* dest, void* source, size_t count)
{
	void* ret = dest;
	
	if (dest <= source || dest >= (source + count))
	{
		//Non-Overlapping Buffers
		//copy from lower addresses to higher addresses
   
		while (count --)
			*dest++ = *source++;
	}
	else
	{
		//Overlapping Buffers
		//copy from higher addresses to lower addresses
       
		dest += count - 1;
		source += count - 1;

		while (count--)
			*dest-- = *source--;l
	}
      
	return ret;
}

六、参考文献

51CTO博客:C语言库函数 Memcpy 和 Memmove 的区别,你知道多少?
CSND博客:memmove和memcpy的区别

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

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

相关文章

如何正确理解和获取S参数

S参数是网络参数&#xff0c;定义了反射波和入射波之间的关系&#xff0c;给定频率的S参数矩阵指定端口反射波b的矢量相对于端口入射波a的矢量&#xff0c;如下所示&#xff1a; bS∙a 在此基础上&#xff0c;如下图所示&#xff0c;为一个常见的双端口网络拓扑图&#xff1a;…

一文简介Maven初级使用

一.概述 Maven是专门用于管理和构建Java项目的工具&#xff0c;它的主要功能有&#xff1a; 提供了一套标准化的项目结构提供了一套标准化的项目构建流程&#xff08;编译&#xff0c;测试&#xff0c;打包&#xff0c;发布&#xff09;提供了一套依赖管理机制 一方面&…

跟着pink老师前端入门教程-day19

一、移动WEB开发之流式布局 1、 移动端基础 1.1 浏览器现状 PC端常见浏览器&#xff1a;360浏览器、谷歌浏览器、火狐浏览器、QQ浏览器、百度浏览器、搜狗浏览器、IE浏览器。 移动端常见浏览器&#xff1a;UC浏览器&#xff0c;QQ浏览器&#xff0c;欧朋浏览器&#xff0…

Intellij Idea的数据库工具 DataGrip

DataGrip DataGrip&#xff1a; IDEA自带&#xff0c;非常好用。智能提示很强大&#xff0c;快捷键跟IDEA自身一致。 如果下载不了 DataGrip&#xff0c;也可以直接用 IDEA 自带的。 常用的快捷键 alt8&#xff1a; 打开数据库Service ctrlshiftF10&#xff1a;打开常用的数…

使用arduino驱动直流减速电机(蓝牙控制)

此篇博客用于记录使用arduino驱动直流减速电机的过程&#xff0c;仅实现简单的功能&#xff1a;PID调速、蓝牙控制 1、直流减速电机简介2、DRV8833电机驱动模块简介3、HC-05蓝牙模块简介电机转动测试4、PID控制5、蓝牙控制电机 1、直流减速电机简介 我在淘宝购买的电机&#x…

Go 中如何检查文件是否存在?可能产生竞态条件?

嗨&#xff0c;大家好&#xff01;本文是系列文章 Go 技巧第十三篇&#xff0c;系列文章查看&#xff1a;Go 语言技巧。 Go 中如何检查文件是否存在呢&#xff1f; 如果你用的是 Python&#xff0c;可通过标准库中 os.path.exists 函数实现。遗憾的是&#xff0c;Go 标准库没有…

pytorch 利用Tensorboar记录训练过程loss变化

文章目录 1. LossHistory日志类定义2. LossHistory类的使用2.1 实例化LossHistory2.2 记录每个epoch的loss2.3 训练结束close掉SummaryWriter 3. 利用Tensorboard 可视化3.1 显示可视化效果 参考 利用Tensorboard记录训练过程中每个epoch的训练loss以及验证loss&#xff0c;便于…

【Java数据结构】单向 不带头 非循环 链表实现

模拟实现LinkedList&#xff1a;下一篇文章 LinkedList底层是双向、不带头结点、非循环的链表 /*** LinkedList的模拟实现*单向 不带头 非循环链表实现*/ class SingleLinkedList {class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val …

【多模态大模型】视觉大模型SAM:如何使模型能够处理任意图像的分割任务?

SAM&#xff1a;如何使模型能够处理任意图像的分割任务&#xff1f; 核心思想起始问题: 如何使模型能够处理任意图像的分割任务&#xff1f;5why分析5so分析 总结子问题1: 如何编码输入图像以适应分割任务&#xff1f;子问题2: 如何处理各种形式的分割提示&#xff1f;子问题3:…

c++之说_10|自定义类型 union 联合体

之前我们说了一些 struct 结构体 现在来了解新的自定义类型 union 联合体 语法 union ptr {void* fptr;CLassFunPtr p;FunPtr p2;ptr& operator(CLassFunPtr ptr){p ptr;return *this;}ptr& operator(FunPtr Fptr){p2 Fptr;return *this;} } FunPtr_; 我们看到了…

第 383 场 LeetCode 周赛题解

A 边界上的蚂蚁 模拟 class Solution { public:int returnToBoundaryCount(vector<int> &nums) {int s 0;int res 0;for (auto x: nums) {s x;if (s 0)res;}return res;} };B 将单词恢复初始状态所需的最短时间 I 枚举&#xff1a;若经过 i i i 秒后 w o r d w…

Leetcode刷题笔记题解(C++):257. 二叉树的所有路径

思路&#xff1a;深度优先搜索 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right…

leetcode 算法 67.二进制求和(python版)

需求 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 示例 1&#xff1a; 输入:a “11”, b “1” 输出&#xff1a;“100” 示例 2&#xff1a; 输入&#xff1a;a “1010”, b “1011” 输出&#xff1a;“10101” 代码 class Solution…

这个门禁考勤技术,看了都说好!

在当今数字化时代&#xff0c;考勤管理对于企业、学校、机构等各类组织至关重要。随着科技的不断进步&#xff0c;传统的考勤方式逐渐显露出效率低、安全性差等问题。 因此&#xff0c;为了应对这些挑战&#xff0c;三维人脸考勤系统作为一项创新的解决方案应运而生。 客户案例…

C#,纽曼-尚克斯-威廉士素数(Newman Shanks Williams prime)的算法与源代码

1 NSW素数 素数是纽曼-尚克斯-威廉士素数&#xff08;Newman-Shanks-Williams prime&#xff0c;简写为NSW素数&#xff09;当且仅当它能写成以下的形式&#xff1a; 1981年M. Newman、D. Shanks和H. C. Williams在研究有限集合时&#xff0c;率先描述了NSW素数。 首几个NSW素…

【经典例子】Java实现2048小游戏(附带源码)

一、游戏回顾 2048游戏是一款数字益智游戏&#xff0c;目标是通过合并相同数字的方块来达到2048这个目标。游戏在一个4x4的方格上进行&#xff0c;每个方格上都有一个数字&#xff08;初始时为2或4&#xff09;。玩家可以通过滑动方向键&#xff08;上、下、左、右&#xff09;…

Java实现用户画像活动推荐系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 兴趣标签模块2.3 活动档案模块2.4 活动报名模块2.5 活动留言模块 三、系统设计3.1 用例设计3.2 业务流程设计3.3 数据流程设计3.4 E-R图设计 四、系统展示五、核心代码5.1 查询兴趣标签5.2 查询活动推荐…

升级GPT4保姆级教程

前言&#xff1a; 2024-01-26开通了GPT4之后至今已经使用了两周&#xff0c;体验下来是真的强&#xff0c;各种GPTs使用起来也很丝滑&#xff0c;不需要自己额外调试。之前看版本计划&#xff0c;2024年会发布GPT5&#xff0c;如果你还没有用上GPT4的话快快来升级体验一下吧&a…

C语言之自定义类型:联合和枚举

目录 1. 联合体类型的声明2. 联合体的特点3. 联合体大小的计算联合的一个练习 4. 枚举类型的声明5. 枚举类型的优点6. 枚举类型的使用 1. 联合体类型的声明 像结构体一样&#xff0c;联合体也是由一个或者多个成员构成&#xff0c;这些成员可以不同的类型 但是编译器只为最大…

机器学习系列4-特征工程

机器学习系列4-特征工程 学习内容来自&#xff1a;谷歌ai学习 https://developers.google.cn/machine-learning/crash-course/framing/check-your-understanding?hlzh-cn 本文作为学习记录自己归纳整理的思维导图 这里写目录标题 机器学习系列4-特征工程一级目录二级目录三…