memmove、memcpy,memcopy简介

memmove、memcpy和memccpy三个函数都是内存的拷贝,从一个缓冲区拷贝到另一个缓冲区。
memmove(void *dest,void*src,int count)
memcpy(void *dest,void *src,int count)
memccpy(void*dest,void*src,int ch,int count)

表头文件: #include <string.h>
定义函数: void *memcpy(void *dest, const void *src, size_t n)
函数说明: memcpy()用来拷贝src所指的内存内容前n个字节到dest所指的内存地址上。与strcpy()不同的是,memcpy()会完整的复制n个字节,不会因为遇到字符串结束'/0'而结束
返回值:   返回指向dest的指针

表头文件: #include <string.h>
定义函数: void *memccpy(void *dest, const void *src, int c, size_t n);
函数说明: memccpy()用来拷贝src所指的内存内容前n个字节到dest所指的地址上。与memcpy()不同的是,memccpy()如果在src中遇到某个特定值(int c)立即停止复制。
返回值:   返回指向dest中值为c的下一个字节指针。返回值为0表示在src所指内存前n个字节中没有值为c的字节。

表头文件: #include <string.h>
定义函数: void *memmove(void *dest, const void *src, size_t n);
函数说明:memmove()是从一个缓冲区移动到另一个缓冲区中。 
返回值:   返回指向dest指针。

当dest <= src 或dest >= src+count时,以上三个函数均不会产生覆盖问题,即源数据不会被更改。
若不在以上范围内,则源数据会被更改。

 

从DESCRIPTION看来,两者的功能基本相同,唯一不同的是,当 dest 和 src 有重叠的时候选用不同的函数可能会造成不同的结果。不妨写个小程序来测一下: 

很简单的小程序!不过已经足以达到我的目的了:)将上面代码gcc之后再运行,结果为:0 1 2 3 0 1 2 3 0 1 。 
再把第13行改成:memmove(&a[4], a, sizeof(int)*6),重新gcc再运行,结果为:0 1 2 3 0 1 2 3 4 5 ! 
呵呵,两者的区别出现了。不过其实这样还不够,继续修改13行: memmove(a, &a[4], sizeof(int)*6) //也就是将源、目的置换一下而已 
重新gcc编译再运行,结果为:4 5 6 7 8 9 6 7 8 9 。 
还不够,继续修改13行为: memcpy(a, &a[4], sizeof(int)*6); gcc并运行,结果仍为: 4 5 6 7 8 9 6 7 8 9 ! 
至此真相已经大白了。对比上面四个结果,不难得出以下结论: 
1. 当 src 和 dest 所指内存区有重叠时,memmove 相对 memcpy 能提供保证:保证能将 src 所指内存区的前 n 个字节正确的拷贝到 dest 所指内存中; 
2. 当 src 地址比 dest 地址高时,两者结果一样。换句话说,memmove 与 memcpy 的区别仅仅体现在 dest 的头部和 src 的尾部有重叠的情况下;

memcpy
代码: 
;***
;memcpy.asm - contains memcpy and memmove routines
;
;       Copyright (c) 1986-1997, Microsoft Corporation. All right reserved.
;
;Purpose:
;       memcpy() copies a source memory buffer to a destination buffer.
;       Overlapping buffers are not treated specially, so propogation may occur.
;       memmove() copies a source memory buffer to a destination buffer.
;       Overlapping buffers are treated specially, to avoid propogation.
;
;*******************************************************************************
;***
;memcpy - Copy source buffer to destination buffer
;
;Purpose:
;       memcpy() copies a source memory buffer to a destination memory buffer.
;       This routine does NOT recognize overlapping buffers, and thus can lead
;       to propogation.
;       For cases where propogation must be avoided, memmove() must be used.
;
;       Algorithm:
       void* memcpy(void* dest, void* source, size_t count)
      {
           void* ret = dest;
          //copy from lower address to higher address
          while (count--)
                  *dest++ = *source++;
 
           return ret;
      }
 
 
memmove
memmove - Copy source buffer to destination buffer
;
;Purpose:
;       memmove() copies a source memory buffer to a destination memory buffer.
;       This routine recognize overlapping buffers to avoid propogation.
;       For cases where propogation is not a problem, memcpy() can be used.
;
;   Algorithm:
    void* memmove(void* dest, void* source, size_t count)
   {
       void* ret = dest;
 
       if (dest <= source || dest >= (source + count))
       {
          //Non-Overlapping Buffers
         //copy from lower addresses to higher addresses
    
         while (count --)
               *dest++ = *source++;
     }
     else
     {
        //Overlapping Buffers
       //copy from higher addresses to lower addresses
 
       dest += count - 1;
       source += count - 1;
       while (count--)
                *dest-- = *source--;
      }
      return ret;
   }



<think>好的,我现在需要详细分析memmovememcpy的区别。首先,我要回忆这两个函数的基本用途,它们都是C语言中的内存操作函数,用于复制内存块的内容。但用户想知道它们的区别,所以我要深入比较两者的不同之处。 首先,我应该从函数原型入手。两者的函数原型看起来一样,都是接受目标指针、源指针和要复制的字节数。那它们的区别可能不在于参数,而在于内部实现或处理内存重叠的方式。 接下来,内存重叠的问题。我记得memcpy可能存在源和目标内存区域重叠时的问题,而memmove能够正确处理这种情况。这时候需要具体说明什么是内存重叠,比如源缓冲区的某部分在目标缓冲区的范围内,这时候复制可能会导致数据被覆盖。例如,当源地址在目标地址之前,并且有部分重叠时,如果直接按字节复制,可能会在复制过程中覆盖尚未复制的数据。此时,memmove可能会采用从后向前复制的方式,避免数据被破坏,而memcpy可能只是简单地从前往后复制,导致数据错误。 然后,性能方面。由于memmove需要处理内存重叠的情况,可能在实现时会有额外的检查,比如判断源和目标的地址关系,从而决定复制的方向(从前往后还是从后往前)。而memcpy可能假设不存在重叠,因此可以更高效地执行,比如使用更快的复制指令或块复制操作。因此,在已知没有内存重叠的情况下,memcpy可能更快,但如果有重叠的可能,就必须用memmove来保证正确性。 另外,函数的安全性和适用场景。使用memcpy时,用户必须确保内存区域不重叠,否则会导致未定义行为。而memmove则更加安全,无论是否存在重叠都能正确处理。因此,在不确定是否有重叠的情况下,应该优先使用memmove。 我还需要举一些例子来具体说明。例如,当需要将数组中的元素向后移动几个位置时,如果直接使用memcpy,可能会导致后面的元素覆盖前面的元素,而使用memmove则能正确处理这种情况。另一个例子是将字符串的一部分复制到另一个位置,如果源和目标有重叠,memmove能够正确复制,而memcpy可能出错。 另外,检查C标准库中的说明。根据C标准,memcpy不处理内存重叠,而memmove会处理。这意味着,即使实现上某些库的memcpy可能处理了重叠的情况,但按照标准,这并不保证,因此编写可移植代码时,必须区分使用。 总结起来,两者的主要区别在于处理内存重叠的能力,以及由此带来的性能差异和使用场景的不同。需要明确在何种情况下使用哪个函数,以确保程序的正确性和效率。 不过,我是否遗漏了其他可能的区别?比如函数的具体实现细节,或者不同平台上的差异?可能还需要提到,虽然memmove更安全,但在没有重叠的情况下,性能可能接近memcpy,但如果有重叠,memmove会稍慢一些。此外,两者的返回值都是目标指针,这在功能上是相同的。 最后,确保回答结构清晰,逐步解释两者的区别,并提供示例帮助用户理解。同时,按照系统级指令的要求,正确使用LaTeX格式,行内公式用$...$,独立公式用$$...$$,但在这个问题中可能涉及的数学表达式不多,但如果有的话需要正确应用。</think>memmovememcpy是C语言中用于内存块复制的函数,主要区别在于**对内存重叠的处理**和**使用场景**。以下是逐步分析: --- ### 1. **函数定义** - **memcpy**: ```c void* memcpy(void* dest, const void* src, size_t n); ``` 将`src`指向的`n`字节数据复制到`dest`指向的内存,**假设源(src)和目标(dest)内存区域不重叠**。 - **memmove**: ```c void* memmove(void* dest, const void* src, size_t n); ``` 功能与`memcpy`相同,但**允许源和目标内存区域重叠**,会正确处理此类情况。 --- ### 2. **关键区别:内存重叠** - **内存重叠**:当`src`和`dest`指向的内存区域有部分重叠时(例如,`src < dest < src + n`),直接复制可能导致数据被覆盖。 - **memcpy**: 不检查重叠,直接按字节复制(通常从前到后)。若存在重叠,**结果未定义**(可能出错)。 - **memmove**: 会检查内存方向,选择**安全的复制顺序**: - 如果`dest`在`src`之后,则从后向前复制(避免覆盖未复制的数据)。 - 如果`dest`在`src`之前,则从前向后复制。 #### 示例: ```c char str[] = "abcdefghi"; // 尝试将"abcde"复制到str[2]的位置(覆盖原有数据) memcpy(str + 2, str, 5); // 未定义行为!可能得到错误结果 memmove(str + 2, str, 5); // 正确:输出结果为 "ababcde" ``` --- ### 3. **性能差异** - **memcpy**: 假设无内存重叠,可能使用更高效的复制方法(如SIMD指令或块复制),**速度更快**。 - **memmove**: 需要额外检查内存方向,性能略低,但安全性更高。 --- ### 4. **使用场景** - **使用memcpy的条件**: - 明确知道`src`和`dest`内存区域**不重叠**。 - 需要更高性能(例如复制大块独立数据)。 - **使用memmove的条件**: - 内存区域**可能重叠**(如数组内元素移动)。 - 不确定是否有重叠时,优先选择`memmove`。 --- ### 5. **总结对比表** | 特性 | memcpy | memmove | |---------------------|-------------------------|-------------------------| | 内存重叠处理 | 不处理(未定义行为) | 自动处理 | | 性能 | 更快 | 稍慢(需额外检查) | | 安全性 | 需手动保证无重叠 | 无需额外检查 | | 典型场景 | 独立内存块复制 | 数组/缓冲区内部数据移动 | --- ### 6. **代码验证示例** ```c #include <stdio.h> #include <string.h> int main() { char str1[] = "123456789"; char str2[] = "123456789"; // 使用memcpy(错误示例) memcpy(str1 + 2, str1, 5); // 未定义行为 printf("memcpy结果: %s\n", str1); // 可能输出异常值,如"121212345" // 使用memmove(正确示例) memmove(str2 + 2, str2, 5); // 正确复制 printf("memmove结果: %s\n", str2); // 输出"1212345789" return 0; } ``` --- ### 结论 - **优先选择memmove**:除非确定无重叠且需要极致性能,否则使用`memmove`更安全。 - **memcpy的适用场景**:复制独立内存块(如结构体、数组到新缓冲区)。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值