C/C++之Memcpy and memmove
2015-08-13 10:01
309 查看
memcpy与memmove的目的都是将N个字节的源内存地址的内容拷贝到目标内存地址中。
但当源内存和目标内存存在重叠时,memcpy会出现错误,而memmove能正确地实施拷贝,但这也增加了一点点开销。
memmove的处理措施:
(1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
(2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
(3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝
-- memcpy实现
Notes:
memcpy的参数指针类型是void*,具体赋值操作是以字节为单位。
必须进行类型转换。
返回的还是void*型的dest。
-- memmove实现
示意图:
s==d时,什么都不做。
d在前,正向拷贝。
d在后,逆向拷贝。
其实在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
注意对于重合的要反向拷贝
/*
*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的长度,这是调用者应该考虑的问题。
但当源内存和目标内存存在重叠时,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++,Windows/MFC_中L和_T()之区别
- C++中各种类型修饰符汇总
- VC++----using namespace std问题
- 值得学习的C语言开源项目
- 我的C++开发工具链
- C++中四种强制类型转换的区别
- java 的jna与C/C++的对应关系
- 【零】ODB - C++ 持久层框架ODB
- eclipse 配置 opencv (c++版)
- c++常见输入方法[持续更新]
- C++ STL标准程序库初探
- OC语言中数组的使用
- C++ primer【笔记】关联容器 map
- 黑马程序员-----------C语言基础-----------分支结构
- C++安全异常std:auto_ptr
- [转载] C++ 多线程编程总结
- VC++ 关于 ON_UPDATE_COMMAND_UI 相关的作用.
- C语言内存分配
- C语言的函数