ZetCode

C memcmp 函数

最后修改:2025 年 4 月 8 日

内存比较是 C 编程的基础,而 memcmp 是用于比较内存位置之间数据的关键函数。本教程将深入介绍 memcmp,包括其语法、用法和潜在的陷阱。我们将探讨实际示例,并讨论对关键应用程序更安全的选择。理解 memcmp 有助于优化内存操作,同时保持程序的安全性和可靠性。

什么是 memcmp?

memcmp 函数逐字节比较两个内存块。它声明在 string.h 中,并接受三个参数:指向两个内存块的指针和要比较的字节数。如果内存块相同,memcmp 返回零;如果第一个不同字节在第一个块中较低,则返回负数;如果较高,则返回正数。与字符串比较函数不同,memcmp 比较所有字节,包括空字节。

memcmp 的基本用法

此示例演示了如何使用 memcmp 比较两个数组。

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

int main() {
    char arr1[] = {1, 2, 3, 4, 5};
    char arr2[] = {1, 2, 3, 4, 5};
    char arr3[] = {1, 2, 3, 4, 6};

    int result1 = memcmp(arr1, arr2, sizeof(arr1));
    int result2 = memcmp(arr1, arr3, sizeof(arr1));

    printf("Comparison 1: %d\n", result1);
    printf("Comparison 2: %d\n", result2);

    return 0;
}

在这里,memcmp 逐字节比较两个数组。第一次比较返回 0,表示内容相同。第二次返回负值,因为 arr1 中的第五个字节 (5) 小于 arr3 中的第五个字节 (6)。比较是基于原始字节进行的,而不是解释后的值。请务必确保大小参数与您预期的比较长度相符。

使用 memcmp 比较字符串

memcmp 可以比较字符串,但与 strcmp 不同,如下例所示。

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

int main() {
    char str1[] = "apple";
    char str2[] = "apples";
    char str3[] = "apple\0extra";

    printf("strcmp(str1, str2): %d\n", strcmp(str1, str2));
    printf("memcmp(str1, str2, 5): %d\n", memcmp(str1, str2, 5));
    printf("memcmp(str1, str3, 6): %d\n", memcmp(str1, str3, 6));

    return 0;
}

此示例显示了 strcmpmemcmp 之间的主要区别。虽然 strcmp 在遇到空终止符时停止,但 memcmp 会比较所有指定的字节。第一次 memcmp 只比较 5 个字节并发现相等。第二次则会比较到空字节。当比较二进制数据或需要将空字节包含在比较中时,memcmp 非常有用。

使用 memcmp 比较结构

此示例演示了如何使用 memcmp 比较结构。

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

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

int main() {
    Student s1 = {101, "Alice", 95.5};
    Student s2 = {101, "Alice", 95.5};
    Student s3 = {102, "Bob", 88.0};

    int result1 = memcmp(&s1, &s2, sizeof(Student));
    int result2 = memcmp(&s1, &s3, sizeof(Student));

    printf("Comparison 1: %d\n", result1);
    printf("Comparison 2: %d\n", result2);

    return 0;
}

在这里,memcmp 逐字节比较整个结构。第一次比较返回 0,因为结构相同。第二次返回非零值,因为它们不同。请注意,填充字节可能会影响比较结果。此方法速度很快,但由于潜在的位级差异,对于包含指针或浮点数的结构可能无法可靠工作。

更安全的替代方案:memcmp_s

此示例演示了 C11 中提供的更安全的 memcmp_s 函数。

safe_compare.c
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>

int main() {
    char data1[5] = {1, 2, 3, 4, 5};
    char data2[10] = {1, 2, 3, 4, 5};
    
    int result;
    errno_t err = memcmp_s(data1, sizeof(data1), 
                      data2, sizeof(data2), 
                      sizeof(data1), &result);

    if (err != 0) {
        printf("Error: Invalid parameters or size mismatch\n");
        return 1;
    }

    printf("Comparison result: %d\n", result);
    return 0;
}

memcmp_s 增加了边界检查,并在参数无效时返回错误。它会检查比较大小是否超过任一缓冲区。函数在成功时返回零,在失败时返回非零。虽然它并非普遍可用,但对于面向 C11 或更高版本且支持边界检查的安全关键代码,建议使用它。

__STDC_WANT_LIB_EXT1__ 定义为 1,明确表示程序希望使用 C11 标准库的可选扩展。没有这个宏,某些更安全的功能,包括 memcmp_s,可能不会由编译器提供。此功能允许开发人员选择性地启用附加功能,以提高其程序的安全性和可靠性。

比较部分数组

此示例展示了如何使用 memcmp 比较数组的各个部分。

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

int main() {
    int arr1[] = {1, 2, 3, 4, 5, 6, 7, 8};
    int arr2[] = {9, 10, 3, 4, 5, 6, 11, 12};
    
    // Compare middle 4 elements (3,4,5,6)
    int result = memcmp(arr1 + 2, arr2 + 2, 4 * sizeof(int));

    if (result == 0) {
        printf("Middle elements are identical\n");
    } else {
        printf("Middle elements differ\n");
    }

    return 0;
}

在这里,memcmp 比较从每个数组的第三个元素开始的四个整数。大小计算为 4 * sizeof(int) 以获得正确的字节数。此技术对于比较数组或缓冲区的特定部分很有用。由于两个数组中的中间元素相同,因此比较返回 0。

使用 memcmp 的最佳实践

来源

C memcmp 文档

本教程介绍了 memcmp 函数,从基本用法到高级注意事项。虽然它功能强大,但请始终小心使用内存操作,以防止程序中的安全漏洞和未定义行为。

作者

我的名字是 Jan Bodnar,我是一名敬业的程序员,对编码充满热情。自 2007 年以来,我通过 1400 多篇文章和 8 本电子书分享我的专业知识。凭借十多年的教学经验,我致力于让编程变得易于理解和引人入胜。

列表 C 标准库