ZetCode

C strcmp 函数

最后修改:2025 年 4 月 8 日

字符串比较是 C 编程的基础,而 strcmp 是按字典顺序比较字符串的关键函数。本教程将深入探讨 strcmp,包括其语法、用法和潜在的陷阱。我们将探讨实际示例,并讨论对关键应用程序更安全的替代方案。理解 strcmp 有助于执行准确的字符串比较,同时保持程序的安全性和可靠性。

什么是 strcmp?

strcmp 函数按字典顺序比较两个字符串。它声明在 string.h 中,并接受两个参数:指向要比较的字符串的指针。strcmp 返回一个整数,指示比较结果:零表示相等,负数表示第一个字符串小于第二个,正数表示第一个字符串大于第二个。对于安全关键代码,请考虑使用 strncmp 进行长度限制的比较或特定于平台的安全版本。

strcmp 的基本用法

此示例演示了使用 strcmp 进行的基本字符串比较。

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

int main() {
    char str1[] = "apple";
    char str2[] = "banana";
    
    int result = strcmp(str1, str2);

    if (result == 0) {
        printf("Strings are equal\n");
    } else if (result < 0) {
        printf("'%s' comes before '%s'\n", str1, str2);
    } else {
        printf("'%s' comes after '%s'\n", str1, str2);
    }

    return 0;
}

在此,strcmp 按字典顺序比较 "apple" 和 "banana"。由于 ASCII 中 'a' 在 'b' 之前,因此该函数返回一个负值。比较是区分大小写的,并且会一直进行,直到找到不同的字符或空终止符。始终确保字符串正确以空字符终止,以避免未定义行为。

不区分大小写的比较

此示例演示了如何使用标准 C 进行不区分大小写的比较。

case_insensitive.c
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int case_insensitive_cmp(const char *s1, const char *s2) {
    while (*s1 && *s2) {
        int diff = tolower(*s1) - tolower(*s2);
        if (diff != 0) return diff;
        s1++;
        s2++;
    }
    return *s1 - *s2;
}

int main() {
    char str1[] = "Apple";
    char str2[] = "apple";
    
    int result = case_insensitive_cmp(str1, str2);

    if (result == 0) {
        printf("Strings are equal (case-insensitive)\n");
    } else {
        printf("Strings are different\n");
    }

    return 0;
}

此自定义函数通过将字符转换为小写字母来不区分大小写地比较字符串。标准 strcmp 是区分大小写的,因此我们需要额外的逻辑来进行不区分大小写的比较。该函数返回零表示字符串相等,遵循 strcmp 的约定。请注意,这比使用 stricmp 等特定于平台的函数更复杂。

比较固定长度的字符串

此示例演示了使用 strncmp 进行更安全的比较。

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

int main() {
    char str1[] = "HelloWorld";
    char str2[] = "HelloMoon";
    
    // Compare first 5 characters only
    int result = strncmp(str1, str2, 5);

    if (result == 0) {
        printf("First 5 characters are equal\n");
    } else {
        printf("First 5 characters are different\n");
    }

    return 0;
}

strncmp 仅比较指定数量的字符,因此对于可能未以空字符终止的字符串更安全。在此,它仅比较每个字符串的前 5 个字符。这在比较固定长度字段或只关心前缀时很有用。与 strcmp 不同,它不会读取超过指定长度的字符,从而降低了缓冲区溢出的风险。

使用 strcmp 对字符串进行排序

此示例显示了如何在排序算法中使用 strcmp

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

#define COUNT 5

void sort_strings(char *arr[], int n) {
    for (int i = 0; i < n-1; i++) {
        for (int j = i+1; j < n; j++) {
            if (strcmp(arr[i], arr[j]) > 0) {
                char *temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

int main() {
    char *fruits[COUNT] = {"banana", "apple", "pear", "orange", "kiwi"};
    
    sort_strings(fruits, COUNT);

    printf("Sorted fruits:\n");
    for (int i = 0; i < COUNT; i++) {
        printf("%s\n", fruits[i]);
    }

    return 0;
}

此代码使用 strcmp 对字符串数组进行排序,以确定字典顺序。冒泡排序算法根据 strcmp 的结果交换字符串。请注意,我们正在交换指针,而不是复制字符串内容。对于生产代码,请考虑更有效的排序算法,例如快速排序。该示例演示了 strcmp 在排序操作中的作用。

安全替代方案:strcmp_s

此示例演示了 C11 中更安全的 strcmp_s 函数。

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

int main() {
    char str1[] = "test";
    char str2[10];
    
    // Simulate potential buffer issue
    strncpy(str2, "test", 4);
    str2[4] = '\0';

    // Safe comparison with additional checks
    errno_t result = strcmp_s(str1, sizeof(str1), str2, sizeof(str2));

    if (result == 0) {
        printf("Strings are equal\n");
    } else if (result > 0) {
        printf("str1 is greater than str2\n");
    } else if (result < 0) {
        printf("str1 is less than str2\n");
    } else {
        printf("Comparison error\n");
    }

    return 0;
}

strcmp_s 添加了运行时约束检查,以防止与无效字符串一起出现未定义行为。它会验证字符串参数是否不为空以及大小是否有效。虽然并非普遍可用,但当针对 C11 或更高标准进行编译时,建议在安全关键代码中使用它。该函数在成功时返回零,其比较结果与 strcmp 匹配。

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

使用 strcmp 的最佳实践

来源

C strcmp 文档

本教程探讨了 strcmp 函数,从基本用法到高级注意事项。虽然它功能强大,但始终要谨慎使用字符串操作,以防止程序中的安全漏洞和未定义行为。

作者

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

列表 C 标准库