memcpy 和 memcmp 函数用法详解

1. memcpy 函数

函数原型

void *memcpy(void *dest, const void *src, size_t n);

功能

将 src 指向的内存区域的 n 个字节复制到 dest 指向的内存区域。源和目标内存区域不能重叠,如果重叠应该使用 memmove

参数

  • dest:目标内存地址指针

  • src:源内存地址指针

  • n:要复制的字节数

使用示例

示例1:复制整型数组
#include <stdio.h>
#include <string.h>

int main(void)
{
    int src[5] = {1, 2, 3, 4, 5};
    int dest[5];
    
    // 复制整个数组
    memcpy(dest, src, sizeof(src));
    
}
示例2:复制部分数据
#include <stdio.h>
#include <string.h>

int main(void)
{
    char src[] = "Hello, World!";
    char dest[20];
    
    // 只复制前5个字符(不包括字符串结束符)
    memcpy(dest, src, 5);

}
示例3:复制结构体
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char name[20];
    float score;
} Student;

int main(void)
{
    Student student1 = {1, "张三", 85.5};
    Student student2;
    
    // 复制整个结构体
    memcpy(&student2, &student1, sizeof(Student));

}
示例4:从数组中间复制数据
#include <stdio.h>
#include <string.h>

int main(void)
{
    int src[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int dest[5];
    
    // 从src的第3个元素开始复制5个元素
    memcpy(dest, &src[2], 5 * sizeof(int));
    
}
示例5:复制到数组中间
#include <stdio.h>
#include <string.h>

int main(void)
{
    int data[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int new_data[3] = {10, 11, 12};
    
    // 将new_data复制到data的第4个位置开始
    memcpy(&data[3], new_data, sizeof(new_data));

}

2. memcmp 函数

函数原型

int memcmp(const void *s1, const void *s2, size_t n);

功能

比较 s1 和 s2 指向的内存区域的前 n 个字节。

参数

  • s1:第一个内存区域指针

  • s2:第二个内存区域指针

  • n:要比较的字节数

返回值

  • 返回 0:两个内存区域的前 n 个字节完全相同

  • 返回 <0:第一个不同的字节,在 s1 中的值小于 s2 中的值(按无符号字符比较)

  • 返回 >0:第一个不同的字节,在 s1 中的值大于 s2 中的值(按无符号字符比较)

使用示例

示例1:比较整型数组
#include <stdio.h>
#include <string.h>

int main(void)
{
    int arr1[5] = {1, 2, 3, 4, 5};
    int arr2[5] = {1, 2, 3, 4, 5};
    int arr3[5] = {1, 2, 3, 4, 6};
    
    // 比较arr1和arr2
    if(memcmp(arr1, arr2, sizeof(arr1)) == 0) {
        printf("arr1 和 arr2 完全相等\n");
    } else {
        printf("arr1 和 arr2 不相等\n");
    }
    
    // 比较arr1和arr3
    int result = memcmp(arr1, arr3, sizeof(arr1));
    if(result == 0) {
        printf("arr1 和 arr3 完全相等\n");
    } else if(result < 0) {
        printf("arr1 小于 arr3\n");  // 因为5 < 6
    } else {
        printf("arr1 大于 arr3\n");
    }
    
}
示例2:比较字符串(包括非字符串数据)
#include <stdio.h>
#include <string.h>

int main(void)
{
    char str1[] = "Hello";
    char str2[] = "Hello";
    char str3[] = "Hellp";  // 最后字符是'p'而不是'o'
    char str4[] = "Hell";   // 少一个字符
    
    // 比较str1和str2的前5个字符
    if(memcmp(str1, str2, 5) == 0) {
        printf("str1 和 str2 前5个字符相等\n");
    }
    
    // 比较str1和str3
    int result = memcmp(str1, str3, 5);
    if(result < 0) {
        printf("str1 小于 str3,因为 'o'(0x6F) < 'p'(0x70)\n");
    }
    
    // 比较str1和str4的前4个字符
    if(memcmp(str1, str4, 4) == 0) {
        printf("str1 和 str4 前4个字符相等\n");
    }
    
    return 0;
}
示例3:比较结构体
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char name[10];
    float score;
} Student;

int main(void)
{
    Student stu1 = {1, "张三", 85.5};
    Student stu2 = {1, "张三", 85.5};
    Student stu3 = {1, "张三", 90.0};
    
    // 比较两个结构体
    if(memcmp(&stu1, &stu2, sizeof(Student)) == 0) {
        printf("stu1 和 stu2 完全相等\n");
    }
    
    // 比较stu1和stu3
    int result = memcmp(&stu1, &stu3, sizeof(Student));
    if(result != 0) {
        printf("stu1 和 stu3 不相等\n");
        // 注意:浮点数比较可能会因为内存表示不同而显示不相等,即使数值相等
    }
    
    return 0;
}
示例4:比较数组的部分数据
#include <stdio.h>
#include <string.h>

int main(void)
{
    unsigned char data1[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};
    unsigned char data2[10] = {0x01, 0x02, 0x03, 0x04, 0xFF, 0x06, 0x07, 0x08, 0x09, 0x0A};
    
    // 比较前4个字节
    if(memcmp(data1, data2, 4) == 0) {
        printf("前4个字节相等\n");
    }
    
    // 比较前5个字节
    int result = memcmp(data1, data2, 5);
    if(result < 0) {
        printf("第5个字节不同: 0x05 < 0xFF\n");
    }
    
    // 比较整个数组
    result = memcmp(data1, data2, sizeof(data1));
    if(result != 0) {
        printf("整个数组不相等\n");
    }
    
}
示例5:与 strcmp 的区别
#include <stdio.h>
#include <string.h>

int main(void)
{
    char str1[] = "Hello";
    char str2[] = "Hello\0World";  // 后面还有内容
    char str3[] = "Hell";          // 少一个字符
    
    // 使用strcmp比较(遇到\0停止)
    printf("strcmp(str1, str2) = %d\n", strcmp(str1, str2));  // 0,因为\0前的内容相同
    
    // 使用memcmp比较指定字节数
    printf("memcmp(str1, str2, 6) = %d\n", memcmp(str1, str2, 6));  // 可能非0,比较包括\0
    
    // 比较不同长度的字符串
    printf("strcmp(str1, str3) = %d\n", strcmp(str1, str3));  // >0,因为"Hello" > "Hell"
    
    // memcmp需要指定长度
    printf("memcmp(str1, str3, 4) = %d\n", memcmp(str1, str3, 4));  // 0,前4个字符相同
    printf("memcmp(str1, str3, 5) = %d\n", memcmp(str1, str3, 5));  // >0,第5个字符不同
    
}

3. 注意事项

memcpy 注意事项

// 1. 内存重叠问题
char str[] = "Hello, World!";
// 错误:源和目标有重叠
// memcpy(str + 7, str, 7);  // 未定义行为

// 正确:使用memmove处理重叠
memmove(str + 7, str, 7);

// 2. 缓冲区溢出
int dest[5];
int src[10] = {1,2,3,4,5,6,7,8,9,10};
// 错误:目标缓冲区太小
// memcpy(dest, src, sizeof(src));  // 缓冲区溢出!

// 正确:确保目标缓冲区足够大
memcpy(dest, src, sizeof(dest));

// 3. 复制对象包含指针
typedef struct {
    char *name;
    int age;
} Person;

Person p1 = {malloc(20), 25};
strcpy(p1.name, "John");
Person p2;

// 注意:这只会复制指针,不会复制指针指向的数据
memcpy(&p2, &p1, sizeof(Person));
// p2.name 和 p1.name 指向同一块内存!

memcmp 注意事项

// 1. 浮点数比较问题
float f1 = 1.0f;
float f2 = 1.0f;
// 注意:浮点数在内存中的表示可能不完全相同
// memcmp(&f1, &f2, sizeof(float)) 可能返回非0,即使数值相等

// 2. 结构体填充字节问题
typedef struct {
    char c;
    int i;
} MyStruct;

MyStruct s1 = {'A', 10};
MyStruct s2 = {'A', 10};
// 结构体可能有填充字节,这些字节的值是不确定的
// memcmp(&s1, &s2, sizeof(MyStruct)) 可能返回非0,即使成员值相同

// 3. 比较带指针的结构体
typedef struct {
    char *ptr;
    int value;
} Data;

Data d1 = {NULL, 10};
Data d2 = {NULL, 10};
// memcmp(&d1, &d2, sizeof(Data)) 会比较指针值,即使都指向NULL
// 但不同的NULL指针在比较时可能产生非0结果

4. 性能提示

  1. memcpy通常比手动循环快:因为编译器会进行优化,甚至使用硬件加速

  2. 对齐访问:如果数据是按字对齐的,memcpy/memcmp性能更好

  3. 小数据量:对于非常小的数据(几个字节),手动循环可能更快

  4. 编译器优化:现代编译器对memcpy/memcmp有很好的优化

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐