库函数的模拟实现(memmove)

  一、memmove函数说明

还是老规矩给大家伙贴上cplusplus的网址。

函数总结:

  1. 重叠安全

    • 即使 destination 和 source 指向的内存区域有重叠,memmove 也能安全地复制数据,因为它使用了一个中间缓冲区。
  2. 数据类型无关性

    • 函数在复制数据时不关心 source 和 destination 指针所指向对象的底层类型。
  3. 二进制复制

    • 数据以二进制形式复制,不检查 source 中是否有终止空字符(null terminator)。
  4. 精确字节数

    • 函数总是精确复制 num 指定的字节数。
  5. 内存大小要求

    • 为了避免溢出,destination 和 source 指向的数组的大小至少应该是 num 字节。

使用 memmove 时,开发者需要确保提供的内存区域大小合适,并且正确处理任何可能的内存重叠问题,以避免数据损坏或程序崩溃。


二、memmove函数使用

#include <stdio.h>
#include <string.h> // 包含memmove函数的头文件

int main() {
    char src[] = "Hello, World!";
    char dest[20]; // 确保目标数组足够大以容纳源数组的内容

    // 将src数组的内容复制到dest数组中
    memmove(dest, src+6, strlen(src) + 1); // 包括空字符'\0'

    printf("Source: %s\n", src);
    printf("Destination after memmove: %s\n", dest);

    return 0;
}

这段代码首先包含了 string.h 头文件,这是使用 memmove 函数所必需的。然后定义了两个字符数组 srcdestsrc 包含了要复制的字符串,而 dest 是目标数组,用于存储复制的数据。我们使用 memmove 函数将 src 的内容复制到 dest,包括字符串的终止空字符 \0。复制完成后,使用 printf 函数打印出源字符串和目标字符串,以展示 memmove 函数的效果。

请注意,这个示例假设 dest 数组的大小足够大,可以容纳 src 数组的全部内容。在实际使用中,你需要根据实际情况调整数组的大小,并确保不会发生缓冲区溢出。


三、memmove模拟实现

#include <stdio.h>
#include <assert.h>
#include <string.h> // 包含size_t类型的定义

void* my_memmove(void* dest, const void* src, size_t count) {
    assert(dest && src);
    void* ret = dest;
    char* d = (char*)dest;
    const char* s = (const char*)src;

    if (s < d && s + count > d) {
        // 逆序复制,因为src在dest之前且有重叠
        s += count - 1;
        d += count - 1;
        while (count--) {
            *d-- = *s--;
        }
    } else {
        // 顺顺序复制,因为src在dest之后或者没有重叠
        while (count--) {
            *d++ = *s++;
        }
    }
    return ret;
}

// 数组的打印
void print(int* arr, size_t sz) {
    for (size_t i = 0; i < sz; i++) {
        printf("%d ", arr[i]);
    }
}

int main() {
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    // 复制从arr[1]开始的5个元素到arr[3]的位置
    my_memmove(arr + 3, arr + 1, 5);
    size_t sz = sizeof(arr) / sizeof(arr[0]);
    print(arr, sz); // 数组的打印
    printf("\n");
    return 0;
}

代码详解:

  1. 自定义 my_memmove 函数

    • 函数原型:void* my_memmove(void* dest, const void* src, size_t count),接受三个参数,分别代表目标内存地址、源内存地址和要复制的字节数。
    • assert(dest && src):确保传入的目标和源地址不为空。
    • void* ret = dest:保存目标地址,以便最后返回。
    • 将目标和源地址转换为 char* 类型,以便按字节操作。
  2. 内存复制逻辑

    • 首先检查 src 和 dest 的相对位置。如果 src 在 dest 之前并且有重叠,使用逆序复制以避免数据覆盖。
    • 如果 src 在 dest 之后或者没有重叠,则使用顺顺序复制。
  3. 逆序复制

    • 当 src 在 dest 之前且有重叠时,将源指针 s 和目标指针 d 都移动到复制区域的末尾,然后逐字节复制,直到 count 减到 0。
  4. 顺顺序复制

    • 当 src 在 dest 之后或者没有重叠时,从 src 的开始位置逐字节复制到 dest 的开始位置,直到 count 减到 0。
  5. 返回值

    • 函数返回目标地址 ret
  6. 打印函数

    • void print(int* arr, size_t sz):定义了一个打印数组的函数,接受一个整型指针和数组的大小。
  7. main 函数

    • 定义了一个整型数组 arr 并初始化。
    • 调用 my_memmove 函数,将 arr 中从索引 1 开始的 5 个元素复制到索引 3 的位置。注意这里 count 应该是元素个数而不是字节数,但因为 sizeof(int) 通常等于 4 字节,所以这里使用 5 作为 count 值是安全的,前提是数组元素大小不超过 4 字节。
    • 计算数组大小 sz 并使用 print 函数打印数组内容。

本期内容到此就结束啦,自己动手实现一下吧。只有自己动手写出来了知识才是自己的哟!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值