C/C++之Memcpy and memmove
memcpy与memmove的目的都是将N个字节的源内存地址的内容拷贝到目标内存地址中。
但当源内存和目标内存存在重叠时,memcpy会出现错误,而memmove能正确地实施拷贝,但这也增加了一点点开销。
memmove的处理措施:
(1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
(2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
(3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝
-- memcpy实现
1 |
void* memcpy(void* dest, const void* src, size_t n) |
2 |
{ |
3 |
char* d = (char*) dest; |
4 |
const char* s = (const char*) src; |
5 |
while(n-–) |
6 |
*d++ = *s++; |
7 |
return dest; |
8 |
} |
Notes:
- memcpy的参数指针类型是void*,具体赋值操作是以字节为单位。
- 必须进行类型转换。
- 返回的还是void*型的dest。
-- memmove实现
01 |
void* memmove(void* dest, const void* src, size_t n) |
02 |
{ |
03 |
char* d = (char*) dest; |
04 |
const char* s = (const char*) src; |
05 |
06 |
if (s>d) |
07 |
{ |
08 |
// start at beginning of s |
09 |
while (n--) |
10 |
*d++ = *s++; |
11 |
} |
12 |
else if (s<d) |
13 |
{ |
14 |
// start at end of s |
15 |
d = d+n-1; |
16 |
s = s+n-1; |
17 |
18 |
while (n--) |
19 |
*d-- = *s--; |
20 |
} |
21 |
return dest; |
22 |
} |
示意图:
(1)内存低端 <-----s-----> <-----d-----> 内存高端 start at end of s
(2)内存低端 <-----s--<==>--d-----> 内存高端 start at end of s
(3)内存低端 <-----sd-----> 内存高端 do nothing
(4)内存低端 <-----d--<==>--s-----> 内存高端 start at beginning of s
(5)内存低端 <-----d-----> <-----s-----> 内存高端 start at beginning of s
Notes:
- s==d时,什么都不做。
- d在前,正向拷贝。
- d在后,逆向拷贝。
1.memmove 函数原型:void *memmove(void *dest, const void *source, size_t count) 返回值说明:返回指向dest的void *指针 参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数 函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。 2.memcpy 函数原型:void *memcpy(void *dest, const void *source, size_t count); 返回值说明:返回指向dest的void *指针 函数说明:memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。
原型:extern char *strcpy(char *dest,char *src); 功能:把src所指由NULL结束的字符串复制到dest所指的数组中。 说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,返回指向dest的指针。
其实在strcpy的实现比较多,但思想是一致的,一般用C来实现,但是memcpy和memmove这样的函数可能是用汇编实现的,并且充分利用块拷贝的思想,不会单字节单字节的拷贝。所以效率strcpy<memcpy.
memmove一般由于要判断内存是否重合,效率也会较memcpy低些。
1 /***
2 * @brief 以字节的方式直接拷贝
3 * 库中实现是以汇编实现,
4 * 其实可以直接调用strncat函数
5 * **/
6 void *memcpy(void *dst,void *src,size_t n)
7 {
8 char *dp = (char *)dst;
9 char *sp = (char *)src;
10 assert((src!=0)&&(dst!=0)&&(n>0));//not null
11 while(n--)
12 *(dp++) = *(sp++);
13 /**!边界*/
14 dp = '\0';
15 return dst;
16 }
memmove
1 void *memmove(void *dst,const void *src,int n)
2 {
3 char *dp = (char *)dst;
4 char *sp = (char *)src;
5 assert((src!=0)&&(dst!=0)&&(n>0));//not null
6 //非重叠
7 //dp < sp
8 //dp > (sp+n)
9 if(dp<sp||(sp+n)>=dp)
10 {
11 while(n--)
12 *(dp++) = *(sp++);
13 *dp = '\0';
14 }else if(sp<dp)//重叠 (此时条件 sp<dp<(sp+n))如果sp==dp则快速的返回
15 {//反向拷贝
16 sp += n;
17 dp += n;
18 *dp = '\0';
19 while(n--)
20 *(--dp) = *(--sp);
21 }
22 return dst;
23 }
注意对于重合的要反向拷贝
/*
*Magicman
*myMemcpy.c
*不调用库函数,实现内存拷贝
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
void *myMemcpy(void *dest, const void *src, int len)
{
assert((dest != NULL) && (src != NULL) && (len >= 0));
if (dest == src)
{
return dest;
}
while (len-- > 0)
{
*(char *)dest++ = *(char *)src++;
}
return dest;
}
int main(int argc, char argv[])
{
char str[20] = "Testing myMemory!";
char pstr[20] = "";
char *pp = str;
int ia[10] = {1,2,3,4,5,6,7,8,9,10};
int ib[10] = {};
int *ip = NULL;
myMemcpy((void *)pstr, (void *)str, sizeof(str));
printf("%s/n", pstr);
printf("%s/n", myMemcpy((void *)pp, (void *)str, 20));
myMemcpy((void *)ib, (void *)ia, 5*sizeof(int));
for (ip = ib; ip < ib + 10; ip++)
{
printf("%d ", *ip);
}
printf("/n");
return 0;
}
让自己实现memcpy库函数,要求考虑特殊情况,两段内存存在覆盖,以及指针为空的情况。
几点结论:
1,memcpy实现从源source中拷贝n个字节到目标destin中,src源数据应该保留。
2,memmove实现移动一块字节,src源数据可以不保留。
3,memcpy没有考虑内存覆盖问题(由assert条件可知);而memmove考虑了内存覆盖问题,并给出了解决办法。
4,memcpy和memmove中不需要考虑数组越界问题,dst的长度应该大于src的长度,这是调用者应该考虑的问题。
C/C++之Memcpy and memmove的更多相关文章
- memcpy vs memmove
[本文连接] http://www.cnblogs.com/hellogiser/p/memcpy_vs_memmove.html [分析] memcpy与memmove的目的都是将N个字节的源内存地 ...
- memcpy与memmove的区别
在面试中经常会被问道memcpy与memove有什么区别? 整理如下: 其实主要在考C的关键字:restrict C库中有两个函数可以从一个位置把字节复制到另一个位置.在C99标准下,它们的原型如下: ...
- C语言实现memcpy和memmove
0.两者比较: memmove用于从src拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中.但复制后src内容会被 ...
- memcpy、memmove、memset及strcpy函数实现和理解
memcpy.memmove.memset及strcpy函数实现和理解 关于memcpy memcpy是C和C++ 中的内存拷贝函数,在C中所需的头文件是#include<string.h> ...
- 关于memcpy和memmove的一点说明
今天看到书上降到memcpy和memmove的区别才突然发现原来两者之间有如此区别,以前只知道这两个函数是 实现同样的功能,没有接触到其不同. memcpy和memmove在MSDN的定义如下: 从两 ...
- strcpy()、memcpy()、memmove()、memset()的内部实现
一直想知道 strcpy().memcpy().memmove().memset()的内部实现 strcpy(), 字符串拷贝. char *strcpy(char *strDest, const c ...
- 第 16 章 C 预处理器和 C 库(string.h 库中的 memcpy() 和 memmove())
/*----------------------------------------- mems.c -- 使用 memcpy() 和 memmove() ---------------------- ...
- 模拟实现memcpy 与 memmove
模拟实现memcpy 与 memmove 1.str系列的函数只能处理字符串——>必须带有'\0'2.memcpy内存处理函数:不涉及'\0',需要包含头文件 string.h3.source的 ...
- memcpy、memmove、memset、memchr、memcmp、strstr详解
第一部分 综述 memcpy.memmove.memset.memchr.memcmp都是C语言中的库函数,在头文件string.h中.memcpy和memmove的作用是拷贝一定长度的内存的内容,m ...
随机推荐
- React 生命周期介绍
[组件生命周期] 一.理论 组件本质上是状态机,输入确定,输出一定确定 生命周期的三个阶段,三者时间是不固定的,只是在逻辑上的分类: 二.初始化阶段: getDefaultProps:获取实例的默认属 ...
- thinkphp---部署在IIS8.0服务器上
最近做了一个项目,使用的是我自己基于thinkphp开发的一套CMS,由于我本地使用的都是apche的环境,即使是线上环境用的也是宝塔面板,但是现在要将thinkphp的系统部署在IIS8.0的环境下 ...
- [实战]MVC5+EF6+MySql企业网盘实战(2)——用户注册
写在前面 上篇文章简单介绍了项目的结构,这篇文章将实现用户的注册.当然关于漂亮的ui,这在追后再去添加了,先将功能实现.也许代码中有不合适的地方,也只有在之后慢慢去优化了. 系列文章 [EF]vs15 ...
- Ucloud云主机无法yum安装处理办法
Ucloud云主机在yum安装的时候出现这个提示 执行一下命令 yum --disablerepo=salttestyum-config-manager --disable salttestyum-c ...
- Ubuntu16.04下编译安装及运行单目ORBSLAM2
官网有源代码和配置教程,地址是 https://github.com/raulmur/ORB_SLAM2 1 安装必要工具 首先,有两个工具是需要提前安装的.即cmake和Git. sudo apt- ...
- UVA 11168 - Airport - [凸包基础题]
题目链接:https://cn.vjudge.net/problem/UVA-11168 题意: 给出平面上的n个点,求一条直线,使得所有的点在该直线的同一侧(可以在该直线上),并且所有点到该直线的距 ...
- Servlet----------用servlet写一个“网站访问量统计“的小案例
package cn.example; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Ser ...
- (1.2)mysql 索引概念
索引的存储分类:mysql目前提供了以下4种索引 [1]B-Tree索引:最常见的索引类型,大部分引擎都支持B树索引 [2]HASH索引:只有Memory引擎支持,使用场景简单 [3]R-Tree索引 ...
- InnoDB: Operating system error number 87 in a file operation. 错误87的解决方法
InnoDB: Operating system error number 87 in a file operation. 错误87的解决方法 140628 8:10:48 [Note] Plugi ...
- 十天精通CSS3(9)
Keyframes介绍 Keyframes被称为关键帧,其类似于Flash中的关键帧.在CSS3中其主要以“@keyframes”开头,后面紧跟着是动画名称加上一对花括号“{…}”,括号中就是一些不同 ...