C语言内存函数详解:memcpy、memmove与memcmp

Owen
Owen
发布时间:2026-10-15 | 6人浏览过
原创

C语言提供了强大的底層内存操作能力,其中 memcpy、memmove 和 memcmp 是最常用的三个标准库函数。它们不仅用于数组和结构体的数据传输,更是理解指针运算和内存布局的关键。

一、memcpy函数:通用内存拷贝

memcpy(Memory Copy)用于将一段内存区域的内容复制到另一段内存区域。与针对字符串的 strcpy 不同,它不依赖于结束符,可以处理任意二进制数据。

第1步:掌握memcpy用法

目的:了解如何将源数据完整复制至目标地址。
入口:包含头文件 #include<string.h>。
动作:调用原型 void* memcpy(void *dest, const void *src, size_t n);。

  • 关键参数:最后一个参数 n 代表需要传输的字节数,而非元素个数。例如在整型数组操作中,若需拷贝4个 int 类型数据,参数应传 4 * sizeof(int)(即8或20等,视系统而定)。
  • 注意:该函数适用于源与目标区域不重叠的情况。若区域发生重叠,结果未定义。
#include<stdio.h>
#include<string.h>

int main()
{
    int arr[10] = {0};
    int arr_src[10] = {1,2,3,4,5,6,7,8,9,10};
    
    // 将源数组的前5个整数(20字节)复制到目标数组
    memcpy(arr, arr_src, 20);
    return 0;
}

第2步:深入理解模拟实现原理

目的:通过手写代码理解 void* 强转与字节级操作的必要性。
入口:新建源文件,定义自定义函数。
动作:编写逻辑如下所示。

由于 void* 指针无法直接进行自增(编译器不知道指向对象的大小),因此必须将其转换为 char*(占1字节)进行遍历。使用临时指针变量保存初始 dest 以便最终返回。

#include<stdio.h>
#include<assert.h>

// 模拟实现 memcpy
void* my_memcpy(const void* dest, const void* src, size_t sum)
{
    assert(dest && src); // 断言指针合法
    void* ret = dest;    // 记录起始地址供返回
    
    while(sum--)
    {
        // 每次只拷贝1个字节
        *(char*)dest = *(char*)src; 
        // 强制转换以完成字节级的指针递增
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }
    return ret;
}

二、memmove函数:处理内存重叠

当源内存区域和目标内存区域发生重叠时,必须使用 memmove。它能保证无论两个区域如何交叠,都能正确搬运数据。

第1步:掌握memmove用法

目的:在数据位置覆盖前先将原数据搬移至安全区。
入口:包含头文件 #include<string.h>。
动作:调用原型 void* memmove(void *dest, const void *src, size_t n);。

示例场景:将数组的前半部分数据移动到后半部分,中间必然存在重叠。

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

int main()
{
    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    
    // 将 arr(起点) 的数据移动到 arr+2(终点),共移动20字节(5个整数)
    // 此时会发生内存重叠
    memmove(arr + 2, arr, 20);
    return 0;
}

第2步:模拟实现中的方向策略

目的:理解为何重叠时必须根据首地址大小判断拷贝方向。
入口:分析 mymemmove 的核心条件分支。
动作:执行以下逻辑:

  1. 情况 A:src > dest(向后移)。
    如将 {1,2,...} 整体向右移。此时前面的数据未被破坏,可以直接从前向后拷贝,不会覆盖尚未拷贝的源数据。
  2. 情况 B:src < dest(向前移/向左挤)。
    如果从前往后拷贝,先拷贝的低地址字节会被新数据覆盖,导致后续拷贝出错。因此必须从后向前拷贝,保护高地址段的原始数据。
#include<stdio.h>
#include<assert.h>

void* my_memmove(const void* dest, const void* src, size_t sum)
{
    assert(dest && src);
    void* ret = dest;
    char* dst = (char*)dest;
    const char* src_data = (const char*)src;
    
    if(src > dest)
    {
        // src > dest: 从前往后拷贝
        while(sum--)
        {
            *dst = *src_data;
            dst++; src_data++;
        }
    }
    else
    {
        // src <= dest: 从后往前拷贝
        while(sum--)
        {
            *(dst + sum) = *(src_data + sum);
        }
    }
    return ret;
}

三、memcmp函数:按字节比较

memcmp 类似于字符串比较函数 strcmp,但它比较的是指定长度的字节序列,而不是以 '\0' 结尾的字符串。它常用于结构体成员或二进制内容的比对。

第1步:掌握memcmp用法

目的:检测两块内存内容是否相同。
入口:包含头文件 #include<string.h>。
动作:调用原型 int memcmp(const void *s1, const void *s2, size_t n);。

  • 返回值:若相等返回 0;若 s1 > s2 返回正数;若 s1 < s2 返回负数。
#include<stdio.h>
#include<string.h>

int main()
{
    int arr1[] = {1, 2, 3, 4, 5};
    int arr2[] = {1, 1, 3, 4, 5};
    
    // 比较前8个字节(2个整数)
    int result = memcmp(arr1, arr2, 8);
    printf("%d\n", result); // 输出为正数,因为第二个整数 2 > 1
    return 0;
}

第2步:模拟实现循环细节

目的:实现逐字节匹配直到发现差异或计数归零。
动作:注意循环内部的判断逻辑:

while(sum--) 
{
    if(*pa != *pb) return *pa - *pb; // 一旦发现不同,立即返回差值
    pa++; pb++; // 字节相同则继续下一位
}
return 0; // 全部走完且都相同,说明完全一致
相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表