浅谈memcpy和memmove的区别

memmovememcpy 都是用来复制内存中的数据,但它们之间有一些关键的区别:

1. 处理重叠内存区域的能力

  • memcpy:

    • 不支持重叠内存区域的复制。
    • 如果源和目标内存区域重叠,memcpy 的行为是未定义的。
    • 通常情况下,memcpy 会直接从源地址复制到目标地址,而不考虑它们是否重叠。
  • memmove:

    • 支持重叠内存区域的复制。
    • 当源和目标内存区域重叠时,memmove 会正确地处理这种情况,确保数据正确复制。
    • memmove 会根据源和目标的相对位置决定是从后向前还是从前向后复制数据,以避免数据被覆盖。

2. 参数

  • memcpy:

    • 函数原型: void *memcpy(void *dest, const void *src, size_t n);
    • 参数说明:
      • dest: 目标内存块的起始地址。
      • src: 源内存块的起始地址。
      • n: 要复制的字节数。
  • memmove:

    • 函数原型: void *memmove(void *dest, const void *src, size_t n);
    • 参数说明:
      • dest: 目标内存块的起始地址。
      • src: 源内存块的起始地址。
      • n: 要复制的字节数。

3. 空终止符处理

  • memcpy:

    • 不会自动添加或处理空终止符。
    • 如果复制的内存块包含字符串,你需要确保复制的字节数包含空终止符,否则复制的字符串将不完整。
  • memmove:

    • 同样不会自动处理空终止符。
    • 如果复制的内存块包含字符串,你也需要确保复制的字节数包含空终止符。

示例

假设有一个字符串 "hello,8world!",并希望将 'w''d' 的字符移动到逗号后面的位置。

使用 memcpy
1#include <stdio.h>
2#include <string.h>
3
4int main()
5{
6    char str[] = {"hello,8world!"};
7    
8    // 复制从 'w' 开始的子字符串到逗号后面
9    memcpy(str + 6, str + 7, 6);  // 复制 'w' 到 'd'
10    
11    // 添加空终止符
12    str[12] = '\0';  // 在 '!' 之前添加空终止符
13    
14    printf("%s\n", str);
15    return 0;
16}

分析

  • 原始状态h e l l o , 8 w o r l d ! \0
  • 修改后h e l l o , w o r l d ! \0

memcpy 的调用 memcpy(str + 6, str + 7, 6);'w''d' 的字符(共 6 个字符)复制到逗号后面的位置。这意味着 'w' 覆盖 '8''o' 覆盖 'w',依此类推,直到 'd' 覆盖 'l'

接下来,str[12] = '\0';'!' 之前添加了一个空终止符 \0,确保字符串在 '!' 处结束。

最终状态:

1h e l l o , w o r l d ! \0
20 1 2 3 4 5 6 7 8 9 10 11 12

输出

因为 memcpy 复制了 'w''d' 的字符,并且在 '!' 之前添加了空终止符 \0,所以字符串现在变成了 "hello,world",并且只有一个感叹号。printf 函数遇到 '!' 后面的空终止符 \0 时会停止输出,因此输出将是 "hello,world"

这种方法使用 memcpy 来完成字符的复制,并手动添加空终止符来确保字符串正确结束。

使用 memmove
1#include <stdio.h>
2#include <string.h>
3
4int main()
5{
6    char str[] = {"hello,8world!"};
7    
8    // 复制从 'w' 开始的子字符串到逗号后面
9    memmove(str + 6, str + 7, 6);  // 复制 'w' 到 'd'
10    
11    // 添加空终止符
12    str[12] = '\0';  // 在 '!' 之前添加空终止符
13    
14    printf("%s\n", str);
15    return 0;
16}

分析

  • 原始状态h e l l o , 8 w o r l d ! \0
  • 修改后h e l l o , w o r l d ! \0

memmove 的调用 memmove(str + 6, str + 7, 6);'w''d' 的字符(共 6 个字符)移动到逗号后面的位置。这意味着 'w' 覆盖 '8''o' 覆盖 'w',依此类推,直到 'd' 覆盖 'l'

接下来,str[12] = '\0';'!' 之前添加了一个空终止符 \0,确保字符串在 '!' 处结束。

最终状态:

1h e l l o , w o r l d ! \0
20 1 2 3 4 5 6 7 8 9 10 11 12

输出

因为 memmove 复制了 'w''d' 的字符,并且在 '!' 之前添加了空终止符 \0,所以字符串现在变成了 "hello,world",并且只有一个感叹号。printf 函数遇到 '!' 后面的空终止符 \0 时会停止输出,因此输出将是 "hello,world"

这种方法使用 memmove 来完成字符的移动,并手动添加空终止符来确保字符串正确结束。

总结

  • 选择:

    • 如果源和目标内存区域不重叠,可以使用 memcpy
    • 如果源和目标内存区域可能重叠,应使用 memmove
  • 注意事项:

    • 不论使用哪个函数,都需要确保复制的字节数正确,特别是当涉及到字符串时。
    • 如果复制的内存块包含字符串,需要确保复制的字节数包括空终止符 \0

思考

        如果第三个参数为7或者8会是什么情况呢?

如果为7 会把最后一位‘\0’直接赋值到‘!’,不用str[12] = '\0';

  • 原始状态h e l l o , 8 w o r l d ! \0
  • 修改后h e l l o , w o r l d ! \0

如果为8呢?

  • 原始状态h e l l o , 8 w o r l d ! \0
  • 修改后h e l l o , w o r l d ! \0 \0

如果>=9呢,会出现什么情况呢 ?

这个时候会越界?还是其他?请大家思考一下。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值