C语言实现memcpy、memmove库函数

目录

  • 引言
  • 一、库函数介绍
  • 二、库函数详解
  • 三、源码实现
    • 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 addresseswhile (count --)*dest++ = *source++;}else{//Overlapping Buffers//copy from higher addresses to lower addressesdest += count - 1;source += count - 1;while (count--)*dest-- = *source--;l}return ret;
}

六、参考文献

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DevOps落地笔记-14|部署流水线:打造一站式部署的关键平台

上一课时我主要介绍了实现自动化测试的范围、流程和结构图&#xff0c;自动化测试是持续集成实践不可或缺的一部分&#xff0c;从而使得软件向高效率和高质量迈进了一大步。持续集成主要关注的是代码是否可以编译成功、是否可以通过单元测试和验收测试等。但持续集成并不能实现…

【C#】Json转资源并加载

Json文件如下 右键修改json文件属性 【代码】读取Json文件内容 string sTemplate string.Empty; Assembly assembly Assembly.GetExecutingAssembly(); string resourceName assembly.GetName().Name.ToString() ".Json.test.json"; using (Stream stream asse…

【Python之Git使用教程001】Git简介与安装

一、简介 Git其实就是一个分布式版本的控制系统&#xff0c;在分布式版本的控制系统&#xff0c;大家都拥有一个完整的版本库&#xff0c;不需要联网也可以提交修改&#xff0c;所以中心服务器就显得不那么重要。由于大家都拥有一个完整的版本库&#xff0c;所有只需要把各自的…

目标检测:2如何生成自己的数据集

目录 1. 数据采集 2. 图像标注 3. 开源已标记数据集 4. 数据集划分 参考&#xff1a; 1. 数据采集 数据采集是深度学习和人工智能任务中至关重要的一步&#xff0c;它为模型提供了必要的训练样本和测试数据。在实际应用中&#xff0c;数据采集的方法多种多样&#xff0c;每…

Python||五城P.M.2.5数据分析与可视化_使用复式柱状图分析各个城市的P.M.2.5月度差异情况(中)

目录 4.上海市空气质量月度差异 5.沈阳市空气质量月度差异 五城P.M.2.5数据分析与可视化_使用复式柱状图分析各个城市的P.M.2.5月度差异情况 4.上海市空气质量月度差异 import numpy as np import pandas as pd import matplotlib.pyplot as plt#读入文件 sh pd.read_csv(./S…

chisel RegInit/UInt/U

val reg RegInit(0.U(8.W)) //ok val reg RegInit(0.UInt(8.W)) //errU 使用在数字 . 后边50.U UInt 使用在IO(new Bundle val a Input(UInt(8.W)) 或者 def counter(max:UInt, a1:UInt) package emptyimport chisel3._ import chisel3.util._class MyCounter extends …

26.云原生ArgoCD高级之ApplicationSet

云原生专栏大纲 文章目录 ApplicationSet介绍ApplicationSet 特性ApplicationSet 安装ApplicationSet 工作原理ApplicationSet 生成器列表类型生成器集群生成器基础使用方法Label Selector 指定集群Values 字段传递额外的参数 git生成器git目录生成参数排除目录git文件生成器矩…

山西电力市场日前价格预测【2024-02-03】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-02-03&#xff09;山西电力市场全天平均日前电价为442.47元/MWh。其中&#xff0c;最高日前电价为633.60元/MWh&#xff0c;预计出现在09:30。最低日前电价为367.07元/MWh&#xff0c;预计…

计算机设计大赛 深度学习 机器视觉 车位识别车道线检测 - python opencv

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) …

Java tomcat 使用spring-task,实现定时任务功能

前言 今天接触到一个需求&#xff0c;需要添加一个定时任务功能&#xff0c;第一反应是启动类EnableScheduling、定时任务方法使用Scheduled实现&#xff0c;导入项目后才发现&#xff0c;这个项目是ssm整合框架的tomcat项目&#xff0c;没有启动类&#xff0c; 于是改变了思路…

机器学习本科课程 实验3 决策树处理分类任务

实验3.1 决策树处理分类任务 使用sklearn.tree.DecisionTreeClassifier完成肿瘤分类&#xff08;breast-cancer&#xff09;计算最大深度为10时&#xff0c;十折交叉验证的精度(accuracy)&#xff0c;查准率(precision)&#xff0c;查全率(recall)&#xff0c;F1值绘制最大深度…

算法学习——华为机考题库8(HJ46 - HJ55)

算法学习——华为机考题库8&#xff08;HJ46 - HJ50&#xff09; HJ46 截取字符串 描述 输入一个字符串和一个整数 k &#xff0c;截取字符串的前k个字符并输出 数据范围&#xff1a; 字符串长度满足 1≤n≤1000 &#xff0c; 1≤k≤n 输入描述&#xff1a; 1.输入待截取的…