memcpy memmove memcmy函数以及如何实现

一、memcpy memmove memcmp的介绍、用法以及注意事项

二、具体实现memcpy memmove memcmp

一、memcpy memmove memcmp介绍、用法以及注意事项

1.1介绍

形如memcpy memmove memcmp的这些函数我们都叫它成员函数,它不被数据的类型所局限,

可以对任意类型的数据进行copy,move,compare的操作。

1.2为什么要有成员函数

在c语言内置的库函数中,已经有了strcpy strcmp strstr等函数,为什么还要有成员函数呢?

主要原因是strcpy strcmp 和strstr函数主要针对字符串进行操作,无法实现对其他数据类型的操作。

1.3如何使用成员函数

我们先在MSDN中查看一下这三个函数的具体参数和返回类型,后面具体实现时不多赘述。

 memcpy是对成员进行复制,memmove实际上也是进行复制,但它在特定情况下能处理memcpy所不能解决的问题,memcmp是对成员进行比较。

三个函数的参数都是一样的,分别是void*dest,void*src,size_t count。第一个参数是要执行操作的目标地址,第二个参数就是提供操作数据的源地址,第三个参数是需要进行操作的字节数。

这说明了这个函数的操作是对数据逐字节的,为了验证这个事实,我用memcmp函数举一个例子。

1.4使用的注意事项。

请看下面一段代码,

#include<stdio.h>
#include<string.h>
int main()
{
    int arr1[] = { 1,0x00001102,5 };
    int arr2[] = { 1,3,5 };
    int ret = memcmp(arr, arr2,8);
    printf("%d", ret);
    return 0;
}

memcmp函数如果在比较每个字节的数据时,找到了比另外一个大的,就返回大于0的数,反之返回小于0的,相等就返回0。arr1数组中的第二个元素0x00001102是一个以16进制表示的数字,在当前机器下是小端存储的方式,故它在内存中应以02 22 11 00的方式存放。

 

 

arr2数组中对应位置元素为3,它在内存中的存储方式为 03 00 00 00,

 从而如果真的是以字节的大小比较的话,第二个字节位的11比00来的大,从而ret应该是一个大于0的数字,我们来看一下结果。

说明memcmp函数确实以字节的形式比较, 其他的函数也是一样,这里就不再举例了。

memcpy函数无法实现对自身的复制,比如。

#include<stdio.h>
#include<string.h>
int main()
{
    int arr[] = {1,2,4,5,6};
    memcpy(arr+1,arr,12);
    for(i = 0;i<sizeof(arr)/sizeof(arr[0]);i++)
    {
        printf("%d",arr[i]);
    }
    return 0;
}

 在某些机器下的运行可能会出现1 1 1 1 6的情况,并不是我们想象中的1,1,2,4,6的情况,也就是memcpy函数无法对自己进行复制操作,像这种目标操作空间和源操作空间有重叠的情况,我们一般用memmove来操作。memcpy的这个缺陷在vs2019下已经得到了优化,是因为vs已经把memcpy实现成和memmove同样的代码。

还有,memcpy遇到‘\0’并不会停下来。

二、memcpy、memmove、memcmp的实现方式

2.1memcpy的实现

#include<assert.h>
void my_memcpy(void* dest, void* src, size_t num)
{
    assert(dest && num);
    while (num--)
    {
        *((char*)dest + num) = *((char*)src + num);
    }
}

首先防止指针参数为空,用assert进行断言。

由于三个函数都是对字节进行操作的,并且他们并不知道传过来的是什么参数,所以需要把两个指针参数强转为char*类型,才能进行指针的运算,只要num非0,我们就一直把数据的每个字节进行交换。

2.2 memmove的实现

假设dest和src的起始位置如上图所示,如果要复制12个字节的数据,那么他们的空间出现了重叠。如果按顺序进行交换,那么第一个复制的是1到3,然后是2到4,当复制到第三个的时候,原本的3已经被换成了开始的1,那么就变成把1复制到5,显然不是我们想要的。那该如何处理?

我们可以从src的最后一个整形数据3开始拷贝,这样3和5,2和4,1和3,就不会出现上面的情况了。

也就是说如果dest的地址大于src,就从src的最后一个元素开始拷贝,反之从第一个元素开始拷贝。 

#include<assert.h>
void my_memmove(void* dest,void* src,size_t num)
{
    assert(dest && src);
    if(dest>src)
    {
        while(num--)
        {
            *((char*)dest+num) = *((char*)src+num);
        }
    }
    else
    {
        int i = 0;
        for(i = 0;i<num;i++)
        {
           *((char*)dest+i) = *((char*)src+i);
        }    
    }
}

我们用一个数组来试一下

 结果是正确的。

2.3memcmp的实现

#include<assert.h>
int my_memcmp(void* dest, void* src, size_t num)
{
    assert(dest && src);
    int i = 0;
    while (i<num)
    {
        if (*((char*)dest + i) > *((char*)src + i))
        {
            return 1;
        }
        else if(*((char*)dest + i) < *((char*)src + i))
        {
            return -1;
        }
        i++;
    }
    return 0;
}

这个代码比较思路比较简单,如果某个字节大就返回1,否则返回-1,循环结束仍无返回就返回0,表示相等。这里的实现方式可能和vs底下的实现方式可能有所不同,不相等的情况vs可能就直接返回数据的差值。

拿一个代码来举一个例子

int main()
{
    int arr1[] = { 1,3,4,5 };
    int arr2[] = { 1,0x00001103 };
    printf("%d", my_memcmp(arr2, arr1, 8));
    return 0;
}

执行的结果

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值