strcmp 是 C 标准库 <string.h> 中的一个函数,用于比较两个字符串。

strcmp 函数的功能和原型
strcmp 函数比较两个以 null 结尾的字符串 s1 和 s2。
函数原型:
int strcmp(const char *s1, const char *s2);
返回值:
- 返回 0:
s1和s2完全相同。 - 返回一个负整数:
s1小于s2。(通常是s1中第一个不匹配字符的 ASCII 码减去s2中对应字符的 ASCII 码) - 返回一个正整数:
s1大于s2。(通常是s1中第一个不匹配字符的 ASCII 码减去s2中对应字符的 ASCII 码)
比较规则:
strcmp 会从左到右逐个字符比较两个字符串的 ASCII 码值,比较在以下两种情况之一发生时停止:

- 遇到第一个不相等的字符。
- 两个字符串都同时到达了结尾(即
\0字符)。
示例:
strcmp("apple", "apple")返回0。strcmp("apple", "banana")返回一个负数(因为 'a' < 'b')。strcmp("banana", "apple")返回一个正数(因为 'b' > 'a')。strcmp("apple", "apples")返回一个负数(因为第一个字符串先结束,相当于在比较\0和 's',而\0的 ASCII 码是 0)。
手动实现 strcmp
理解了功能后,我们可以自己动手实现一个 strcmp 函数,核心思想就是循环比较字符,直到找到差异或字符串结束。
最基础的实现
这是最直观、最容易理解的实现方式。
/**
* @brief 自定义 strcmp 函数实现
* @param s1 第一个字符串
* @param s2 第二个字符串
* @return s1 == s2, 返回 0;
* s1 < s2, 返回一个负数;
* s1 > s2, 返回一个正数.
*/
int my_strcmp(const char *s1, const char *s2) {
// 循环,直到 s1 或 s2 指向 '\0',或者两个字符不相等
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2) {
s1++; // 移动到 s1 的下一个字符
s2++; // 移动到 s2 的下一个字符
}
// 循环结束后,*s1 和 *s2 要么是 '\0',要么是不相等的字符
// 将这两个字符相减,结果就是 strcmp 规定的返回值
// s1 是 "abc" s2 是 "abd",*s1 是 'c', *s2 是 'd','c' - 'd' 是一个负数
// s1 是 "abc" s2 是 "ab",*s1 是 'c', *s2 是 '\0','c' - '\0' 是一个正数
// s1 是 "ab" s2 是 "abc",*s1 是 '\0', *s2 是 'c','\0' - 'c' 是一个负数
return *s1 - *s2;
}
代码解析:

while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2): 这是循环条件。*s1 != '\0' && *s2 != '\0': 确保两个字符串都还没有结束。*s1 == *s2: 确保当前字符是相等的。- 只有当这三个条件都满足时,循环才会继续,意味着字符串仍然“相同”。
s1++; s2++;: 如果当前字符相同,就将指针移动到下一个字符进行比较。return *s1 - *s2;: 当循环退出时,说明要么有一个字符串结束了,要么找到了不匹配的字符,将两个指针当前所指向的字符相减,其差值就完全符合strcmp的返回值要求。
更紧凑的实现
我们可以将版本一的逻辑进行简化,利用 C 语言中布尔表达式的特性。
int my_strcmp_compact(const char *s1, const char *s2) {
// 循环直到找到不匹配的字符或任一字符串结束
while (*s1 == *s2) {
// s1 指向了 '\0',s2 也必然指向 '\0'(因为 *s1 == *s2)
// 此时循环会结束,*s1 和 *s2 都是 '\0'
if (*s1 == '\0') {
return 0; // 字符串完全相同
}
s1++;
s2++;
}
// 循环结束,说明 *s1 不等于 *s2
return *(unsigned char *)s1 - *(unsigned char *)s2;
}
或者更进一步,直接利用循环结束后的状态:
int my_strcmp_compact_2(const char *s1, const char *s2) {
while (*s1 && *s1 == *s2) { // *s1 会自动判断是否为 '\0'
s1++;
s2++;
}
// 当循环退出时,要么 *s1 是 '\0',要么 *s1 != *s2
// 将其差值返回即可
return *(const unsigned char *)s1 - *(const unsigned char *)s2;
}
这个版本更简洁,但版本一可能对初学者来说逻辑更清晰。
一个重要的细节:unsigned char
在标准的 strcmp 实现中,字符通常被转换为 unsigned char 类型后再进行比较,这主要是为了处理字符的符号问题。
在 C 语言中,char 类型可能是 signed char(范围 -128 到 127)或 unsigned char(范围 0 到 255),这取决于编译器的实现。char 是 signed 的,ASCII 码大于 127 的字符(或某些非 ASCII 字符)会被解释为负数。
如果我们直接比较两个 char,其中一个可能是负数,另一个是正数,可能会导致意外的结果,比较 '\xff' 和 '\x01':
char是signed的,'\xff'会被解释为 -1。'\x01'是 1。-1 < 1的结果是true。- 但如果我们把它们当作无符号数,
255 > 1。
标准库为了保证比较是基于字符的原始数值(0-255),通常会进行类型转换。
一个更健壮的实现是:
/**
* @brief 更健壮的 strcmp 实现,考虑了 char 的符号问题
*/
int my_strcmp_robust(const char *s1, const char *s2) {
while (1) {
unsigned char c1 = *s1;
unsigned char c2 = *s2;
if (c1 != c2) {
return c1 - c2;
}
if (c1 == '\0') { // c2 也必然是 '\0'
return 0;
}
s1++;
s2++;
}
}
这个版本明确地将字符转换为 unsigned char,确保了比较行为的一致性,不受平台 char 类型默认符号的影响。
完整示例代码
下面是一个完整的 C 程序,演示了如何使用我们自己实现的 my_strcmp 函数,并与标准库的 strcmp 进行对比。
#include <stdio.h>
// 版本一:基础实现
int my_strcmp(const char *s1, const char *s2) {
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2) {
s1++;
s2++;
}
return *s1 - *s2;
}
int main() {
const char *str1 = "hello";
const char *str2 = "hello";
const char *str3 = "world";
const char *str4 = "hell";
const char *str5 = "hellO";
printf("比较 \"%s\" 和 \"%s\":\n", str1, str2);
printf("标准库 strcmp: %d\n", strcmp(str1, str2));
printf("自定义 my_strcmp: %d\n\n", my_strcmp(str1, str2));
printf("比较 \"%s\" 和 \"%s\":\n", str1, str3);
printf("标准库 strcmp: %d\n", strcmp(str1, str3));
printf("自定义 my_strcmp: %d\n\n", my_strcmp(str1, str3));
printf("比较 \"%s\" 和 \"%s\":\n", str1, str4);
printf("标准库 strcmp: %d\n", strcmp(str1, str4));
printf("自定义 my_strcmp: %d\n\n", my_strcmp(str1, str4));
printf("比较 \"%s\" 和 \"%s\":\n", str1, str5);
printf("标准库 strcmp: %d\n", strcmp(str1, str5));
printf("自定义 my_strcmp: %d\n\n", my_strcmp(str1, str5));
return 0;
}
可能的输出:
比较 "hello" 和 "hello":
标准库 strcmp: 0
自定义 my_strcmp: 0
比较 "hello" 和 "world":
标准库 strcmp: -15
自定义 my_strcmp: -15
比较 "hello" 和 "hell":
标准库 strcmp: 111
自定义 my_strcmp: 111
比较 "hello" 和 "hellO":
标准库 strcmp: -79
自定义 my_strcmp: -79
(注:'o' - 'O' 的具体值取决于你的系统字符集,但结果会是同一个负数)
实现 strcmp 的核心步骤是:
- 使用一个
while循环来遍历两个字符串。 - 在循环条件中,判断当前字符是否相等,并且两个字符串是否都未结束。
- 当循环结束时,第一个不相等字符的差值就是最终结果。
- 为了更好的可移植性,最好将字符转换为
unsigned char类型后再进行比较。
希望这个详细的解释能帮助你完全理解 strcmp 函数的原理和实现!
