ZetCode

C memchr 函数

最后修改:2025 年 4 月 8 日

内存操作在 C 编程中是基础的,而 memchr 是在内存块中搜索字符的关键函数。本教程将深入介绍 memchr,包括其语法、用法和潜在的陷阱。我们将探讨实际示例,并讨论对关键应用更安全的替代方案。理解 memchr 有助于在维护程序安全性和可靠性的同时高效地搜索内存。

什么是 memchr?

memchr 函数在内存块中搜索字符的第一次出现。它声明在 string.h 中,并接受三个参数:指向内存的指针、要查找的字符以及搜索大小。memchr 执行二分搜索,不检查空终止符。对于字符串操作,strchr 可能更合适,因为它会处理以空字符结尾的字符串。

memchr 的基本用法

此示例演示了如何使用 memchr 在内存块中搜索字符。

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

int main() {
    char data[] = "Hello, World!";
    char *result;
    char target = 'W';

    // Search for 'W' in first 13 bytes
    result = memchr(data, target, 13);

    if (result != NULL) {
        printf("Found '%c' at position %ld\n", target, result - data);
    } else {
        printf("Character '%c' not found\n", target);
    }

    return 0;
}

这里,memchrdata 的前 13 个字节中搜索 'W'。如果找不到,它将返回指向找到的字符的指针或 NULL。位置是通过指针算术计算的。这对于二进制数据搜索非常高效。在使用结果之前,请始终检查返回值。

在二进制数据中搜索

memchr 可以搜索二进制数据,正如这个包含整数数组的示例所示。

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

int main() {
    int numbers[] = {10, 20, 30, 40, 50};
    int target = 30;
    void *result;

    // Search for value 30 in the array
    result = memchr(numbers, target, sizeof(numbers));

    if (result != NULL) {
        size_t pos = ((int*)result - numbers);
        printf("Found %d at index %zu\n", target, pos);
    } else {
        printf("%d not found in array\n", target);
    }

    return 0;
}

此示例在数组中搜索整数 30。请注意,这仅在字节表示完全匹配时才有效。在类型转换后,通过指针算术计算位置。此技术对于原始内存搜索非常有用。在使用二进制数据时,请注意字节序和对齐问题。

区分大小写的搜索

此示例演示了使用 memchr 进行区分大小写的搜索。

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

int main() {
    char text[] = "CaseSensitiveSearch";
    char lower_target = 's';
    char upper_target = 'S';
    char *result;

    // Search for lowercase 's'
    result = memchr(text, lower_target, strlen(text));
    printf("Lowercase 's' %s\n", result ? "found" : "not found");

    // Search for uppercase 'S'
    result = memchr(text, upper_target, strlen(text));
    printf("Uppercase 'S' %s\n", result ? "found" : "not found");

    return 0;
}

memchr 执行精确的字节匹配,因此它是区分大小写的。此示例显示了搜索 's' 和 'S' 的不同结果。对于不区分大小写的搜索,需要进行额外的处理。该函数会检查整个字符串长度。这种行为与 C 中大多数低级内存操作一致。

带有大小限制的搜索

此示例显示了如何使用 memchr 限制搜索范围。

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

int main() {
    char data[] = "SearchInPartOfTheBuffer";
    char target = 'O';
    size_t search_len = 10; // Only search first 10 bytes

    char *result = memchr(data, target, search_len);

    if (result) {
        printf("Found '%c' in first %zu bytes\n", target, search_len);
    } else {
        printf("'%c' not found in first %zu bytes\n", target, search_len);
    }

    return 0;
}

在这里,memchr 只搜索缓冲区的前 10 个字节。目标 'O' 出现在字符串的后面,但不会被找到。这在处理部分缓冲区或特定内存区域时很有用。请始终确保大小参数不超过实际缓冲区大小。这可以防止读取无效的内存区域。

更安全的替代方案:memchr_s

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

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

int main() {
    char buffer[20] = "SafeSearchExample";
    char target = 'x';
    void *result;
    
    // Safe search with bounds checking
    errno_t err = memchr_s(buffer, sizeof(buffer), target, 
                 sizeof(buffer), &result);

    if (err == 0 && result != NULL) {
        printf("Found '%c' at position %ld\n", 
               target, (char*)result - buffer);
    } else {
        printf("Character '%c' not found or error occurred\n", target);
    }

    return 0;
}

memchr_s 增加了边界检查,并在参数无效时返回错误。这有助于防止缓冲区溢出。该函数成功时返回零,失败时返回非零。虽然它并非普遍可用,但对于安全关键代码推荐使用。结果通过指针参数返回,而不是直接返回。

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

使用 memchr 的最佳实践

来源

C memchr 文档

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

作者

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

列表 C 标准库