内存拷贝函数之memcpy函数和memmove函数

memcpy函数:

函数用途: 将一个指针指向的内存拷贝至另外一个指针指向的内容.

函数原型: void* memcpy(void* destination, const void* source, size_t num);

void*是为了让这个函数可以拷贝所有类型的指针对应的内存而不是某种特定指针, num是拷贝的字节数.

代码演示:

#include <stdio.h>
#include <string.h>

int main() {
    int arr1[20] = { 0 };
    int arr2[20] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    memcpy(arr1, arr2, sizeof(arr2)); // 将arr2复制至arr1.
    for (int i = 0; i < 10; ++i)
        printf("%d%c", arr1[i], " \n"[i == 9]);
    return 0;
}

运行截图:

 自己模拟实现memcpy函数:

#include <stdio.h>
#include <string.h>

void* mymemcpy(void* destination, const void* source, int num) {
    void* res = destination;
    while (num--) {
        *((char*)destination) = *((char*)source);
        destination = (char*)destination + 1;
        source = (char*)source + 1;
    }
    return res;
}

int main() {
    int arr1[20] = { 0 };
    int arr2[20] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    mymemcpy(arr1, arr2, sizeof(arr2));
    for (int i = 0; i < 10; ++i)
        printf("%d%c", arr1[i], " \n"[i == 9]);
    return 0;
}

原理就是强转换成char*指针, 一个一个字节的复制拷贝过去, 最后返回拷贝完的指针.

注意:不同编译器下的memcpy函数实现可能不同, 存在有编译器无法支持该函数拷贝自己的某个片段至自己的某个片段.

如下:

#include <stdio.h>
#include <string.h>

void* mymemcpy(void* destination, const void* source, int num) {
    void* res = destination;
    while (num--) {
        *((char*)destination) = *((char*)source);
        destination = (char*)destination + 1;
        source = (char*)source + 1;
    }
    return res;
}

int main() {
    int arr1[20] = { 0 };
    int arr2[20] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    mymemcpy(arr2 + 2, arr2, sizeof(int) * 5);
    for (int i = 0; i < 10; ++i)
        printf("%d%c", arr2[i], " \n"[i == 9]);
    return 0;
}

有些编译器能显示出正确答案: 1 2 1 2 3 4 5 8 9 10.

但是也有编译器显示出如下答案:

这是因为第三位元素开始拷贝本数组, 第一次改完变成1 2 1 4 5 6......, 第二次变成1 2 1 2 5 6..., 第三次发现原来的3已经被拷贝变成1了, 这样的拷贝导致数据被覆盖, 无法访问到之前没被覆盖到的数据, 所以会出现1 2 1 2 1 2 1 8 9 10的情况, 所以memcpy函数不推荐用于自身拷贝自身, 如果要使用建议使用memmove函数.

 memmove函数:

作用与memcpy函数一样, 但是可以成功地实现自身拷贝自身的操作.

原理模拟实现:

#include <stdio.h>

void* mymemmove(void* destination, const void* source, int num) {
    void* res = destination;
    if (destination < source) {
        while (num--) {
            *((char*)destination) = *((char*)source);
            destination = (char*)destination + 1;
            source = (char*)source + 1;
        }
    } else {
        while (num--) {
            *((char*)destination + num) = *((char*)source + num);
        }
    }
    return res;
}

int main() {
    int arr1[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    mymemmove(arr1, arr1 + 2, 20);
    for (int i = 0; i < 10; ++i)
        printf("%d%c", arr1[i], " \n"[i == 9]);
    return 0;
}

原理是比较地址谁大谁小来决定从前向后复制还是从后向前复制. 当待被复制的字符串在小地址处选择从前往后复制, 这样不会有覆盖的问题, 当待被复制的字符串的大地址处则选择从后往前复制.

具体可以自行画图理解.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值