void *memcpy(void *dst, const void *src, size_t len) { if(NULL == dst || NULL == src){ return NULL; } void *ret = dst; if(dst <= src || (char *)dst >= (char *)src + len){ //没有内存重叠,从低地址开始复制 while(len--){ *(char *)dst = *(char *)src; dst = (char *)dst + 1; src = (char *)src + 1; } }else{ //有内存重叠,从高地址开始复制 src = (char *)src + len - 1; dst = (char *)dst + len - 1; while(len--){ *(char *)dst = *(char *)src; dst = (char *)dst - 1; src = (char *)src - 1; } } return ret; }
在linux中,memcpy是不考虑内存重叠的隐患问题的,即方法一; memcpy的改进版,考虑上内存重叠问题,就是memmove,即方法二。 方法一: void *memcpy(void *dest, const void *src, size_t n) { char *tmp = (char *)dest; char *s = (char *)src; while (n--) *tmp++ = *s++; return dest; } 方法二: void *memmove(void *dest, const void *src, size_t n) { char *tmp, *s; if (dest <= src) //没有内存重叠,从低地址开始复制 { tmp = (char *) dest; s = (char *) src; while (n--) *tmp++ = *s++; } else //有内存重叠,从高地址开始复制 { tmp = (char *) dest + n; s = (char *) src + n; while (n--) *--tmp = *--s; } return dest; }
/* **实现 memcpy **2015.11.3 */ #include <stdio.h> #include <assert.h> #include <string.h> void *my_memcpy(void *dst,const void *src,size_t num) { assert(dst != NULL && src != NULL); void *ret = dst; int wordnum = num / sizeof(int);//按int字长拷贝 int slice = num % sizeof(int);//按char字节拷贝 //当src与dst相交,并且dst在右侧(低地址-->>高地址) if(dst >= src && (char *)dst <= (char *)src + num - 1)//内存重叠高地址判断 { dst = (char *)dst + num; src = (char *)src + num; while(wordnum--) { //*(int *)dst-- = *(int *)src--; //这样写实际只移动了一位 dst = (int *)dst - 1; //应该先移位后复制 src = (int *)src - 1; *(int *)dst = *(int *)src; } while(slice--) { dst = (char *)dst - 1; src = (char *)src - 1; *(char *)dst = *(char *)src; } } //处理正常情况,也可以处理当src与dst相交,并且dst在左侧(低地址-->>高地址) else { while(wordnum--) { *(int *)dst = *(int *)src; dst = (int *)dst + 1; src = (int *)src + 1; } while(slice--) *(char *)dst++ = *(char *)src++; } return ret; } int main() { char a[10]; char b[20] = {"hello"}; //取20方便调试内存重叠 // my_memcpy(a,b,strlen(b)+1); // printf("b = %s\n",b); // printf("a = %s\n",a); my_memcpy(b+2,b,strlen(b)+1); //right printf("b = %s\n",b); printf("b+2 = %s\n",b+2); // printf("b+2 = %s\n",b+2); //right // printf("b = %s\n",b); // my_memcpy(b,b+2,strlen(b+2)+1); // printf("b+2 = %s\n",b+2); // printf("b = %s\n",b); return 0; }
//方法一:不考虑内存重叠 void* memcpy(void *dest, void *src, size_t size) { if(dest == nullptr || src == nullptr) return nullptr; void *result = dest; while(size--) { *(char*)dest = *(char*)src; dest = (char*)dest+1; src = (char*)src+1; } return result; } //方法二:考虑内存重叠(类似于memmove) void *memcpy(void *dest, void *src, size_t size) { if(dest == nullptr || src == nullptr) return nullptr; void *result = dest; if(dest < src || (char*)src+size < (char*)dest)//没有内存重叠 { while(size--) { *(char*)dest = *(char*)src; dest = (char*)dest+1; src = (char*)src+1; } } else//有内存重叠 { dest = (char*)dest+size-1; src = (char*)src+size-1; while(size--) { *(char*)dest = *(char*)src; dest = (char*)dest-1; src = (char*)src-1; } } return result; }
函数原型:void *memcpy(void*dest, const void *src, size_t n);
用法:#include<string.h>
功能:从源src所指的内存地址的起始位置开始,拷贝n个字节的数据到目标dest所指的内存地址的起始位置中。
说明:
1)src和dest所指内存区域不能重叠,函数返回指向dest的指针。如果src和dest以任何形式出现了重叠,它的结果是未定义的。
2)与strcpy相比,memcpy遇到’\0’不结束,而且一定会复制完n个字节。只要保证src开始有n字节的有效数据,dest开始有n字
节内存空间就行。
3)如果目标数组本身已有数据,执行memcpy之后,将覆盖原有数据(最多覆盖n个)。
如果要追加数据,则每次执行memcpy()后,要将目标地址增加到要追加数据的地址。
4)source和destin都不一定是数组,任意的可读写的空间均可。
实现memcpy库函数:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
void * memcpy(void * dst,void * src, size_t s)
{
const char * psrc = static_cast<const char *>(src);
const char * pdst = static_cast<const char *>(dst); //类型强制转换成char * 型
if(psrc==NULL||pdst==NULL)
return NULL;
if(pdst>psrc && pdst<(psrc+s)) //指的是两个区间有重合
{
for(size_t i=s-1;i!=-1;i--)
pdst[i]=psrc[i];
}
else
{
for(size_t i=0;i<s;i++)
pdst[i]=psrc[i];
}
return dst;
}
int main()
{
char buf[100]="abcdefghijk";
memcpy(buf+2,buf,5);
printf("%s\n",buf+2);
return 0;
}
// // Created by yudw on 2017/8/6. // #pragma once #include <iostream> #define debug_ namespace yudw { // 注意当内存有重叠时,src部分会被覆盖 void* memcpy(void *dst, const void* src, size_t size) { if(dst == nullptr || src == nullptr) { return nullptr; } char *pdst = static_cast<char*>(dst); const char *psrc = static_cast<const char*>(src); // 1.内存无重叠 // [dst + 0, dst + size -1] , [src + 0, src + size -1], [dst + 0, dst + size -1] if(pdst + size <= src || pdst >= psrc + size) { #ifdef debug_ std::cout<<"no cover:"; #endif while(size--) { *pdst++ = *psrc++; } } else // 2.内存有重叠 { if(pdst < psrc) // 2.1 dst 在左,有部分重叠,从前往后直接拷贝就行 { #ifdef debug_ std::cout<<"left cover:"; #endif while(size--) { *pdst++ = *psrc++; } } else // 2.2 dst 在右侧, 有部分重叠,从后向前拷贝,src重复部分会被dst覆盖 { #ifdef debug_ std::cout<<"right cover:"; #endif while(size--) { *(pdst + size) = *(psrc + size); } } } return dst; } }
void mymemcpy(void *dst, const void *src, size_t num) { assert((dst != NULL) && (src != NULL)); const char *psrc = (const char*) src; char* pdst = (char*)dst; if (pdst > psrc && pest < psrc + num) { for (int i = num - 1;i != -1; --i) { pdst[i] = psrc[i]; } } else { for (size_t i = 0;i < num;i++) { pdst[i] = psrc[i]; } } }