【C/C++】通过无类型指针实现泛型拷贝(内存拷贝)

无类型指针的缺陷是无法对类型进行解释。(不能计算无类型的大小)

如,定义一个无类型指针:void *p

不能进行++p或者*p的操作,因为系统没有此地址指向对象大小的信息。

 

无内存重叠(从低地址开始复制)

头文件string.h中定义的memcpy()函数可以实现泛型的拷贝。

函数memcpy()

原型:void* memcpy(void *dest,void *src,unsigned int n)

作用:由src所指内存区域复制n个字节到dest所指内存区域。

说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。

 

现在我们编写自己的函数来实现泛型的拷贝。

void* my_memcpy(void *dst,const void *src,int size)
{
	if(di==NULL||si==NULL)
		return;
        void *ret=dst;
	char *d=(char *)dst;
	const char *s=(const char *)src;
	for(int i=0;i<size;i++)
	{
		d[i]=s[i];
	}
        return ret;
}

参数size表示字节个数。

之所以将无类型指针强转为char型指针,只是因为char类型的大小是1字节,这样声明可以实现一个字节一个字节地复制。

主函数中调用这个函数:

int ar[10]={12,23,34,45,56,67,78,89,90,100};

int br[10];

float dr[10]={1.2,2.3,3.4,4.5,6.7,8.9,9.0,10.0};

float xr[10];

my_memcpy(br,ar,sizeof(ar)); //40

my_memcpy(xr,dr,sizeof(dr)); //80

 

进一步,还可以通过泛型拷贝来实现泛型的交换函数。

#include<stdio.h>
struct Student
{
    int id;
    char name[20];
    int age;
};
void Swap(void *a,void *b,int const n)
{
    if(a==NULL||b==NULL)
    {
        return;
    }
    char temp;
    for(int i=0;i<n;++i)
    {
        temp=((char *)a)[i];
        ((char *)a)[i]=((char *)b)[i];
        ((char *)b)[i]=temp;
    }
}
void main()
{
    char ca='a',cb='x';
    int ia=12,ib=23;
    double da=12.23,db=34.34;
    Student sa={2017,"yhping",18};
    Student sb={2018,"xcving",15};
    Swap(&ca,&cb,sizeof(ca));
	Swap(&da,&db,sizeof(da));
	Swap(&sa,&sb,sizeof(sa));
}

 

有内存重叠(从高地址开始复制)

当有内存重叠时,源地址src会被覆盖,因此有了memcpy()函数的改进版memmove()函数。

可以根据判断源地址和目的地址的大小,决定是从低地址开始拷贝还是从高地址开始拷贝。

void* my_memmove(void *dst,const void *src,int size)
{
    if(dst==NULL||src==NULL)
        return;
    void * ret = dst;
    if(dst <= src || (char *)dst >= ((char *)src + size))    //没有内存重叠,从低地址开始复制
    {    
        while(size--)
        {   
            *(char *)dst = *(char *)src;
            dst = (char *)dst + 1;   
            src = (char *)src + 1; 
        } 
    }
    else    //有内存重叠,从高地址开始复制
    {    
        src = (char *)src + len - 1;  
        dst = (char *)dst + len - 1;  
        while(size--)
        {   
            *(char *)dst = *(char *)src;   
            dst = (char *)dst - 1;   
            src = (char *)src - 1;  
        } 
    } 
    return ret;
}

相对全面的测试用例如下:

void Test()
{
    char p1[256] = "hello,world!";
    char p2[256] = {0};
    my_memmove(p2,p1,strlen(p1)+1);
    printf("%s\n",p2);
    my_memmove(NULL,p1,strlen(p1)+1);
    my_memmove(p2,NULL,strlen(p1)+1);
    my_memmove(p1+1,p1,strlen(p1)+1);
    printf("%s\n",p1);
    my_memmove(p1,p1+1,strlen(p1)+1);
    printf("%s\n",p1);
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值