news 2026/5/25 11:29:36

Linux环境下的C语言编程(四十五)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux环境下的C语言编程(四十五)

字符串比较

基本比较

#include <stdio.h> #include <string.h> int main() { // 基本比较示例 const char *str1 = "apple"; const char *str2 = "banana"; const char *str3 = "apple"; const char *str4 = "Apple"; // 注意:首字母大写 printf("基础比较演示:\n"); printf("strcmp(\"%s\", \"%s\") = %d\n", str1, str2, strcmp(str1, str2)); printf("strcmp(\"%s\", \"%s\") = %d\n", str2, str1, strcmp(str2, str1)); printf("strcmp(\"%s\", \"%s\") = %d\n", str1, str3, strcmp(str1, str3)); printf("strcmp(\"%s\", \"%s\") = %d\n", str1, str4, strcmp(str1, str4)); return 0; }

输出结果分析

strcmp("apple", "banana") = -1 (或负数) strcmp("banana", "apple") = 1 (或正数) strcmp("apple", "apple") = 0 strcmp("apple", "Apple") = 32 (或正数,'a' - 'A' = 97 - 65 = 32)

3.1.2 strcmp的返回值真相

strcmp的实际返回值是实现定义的,但标准保证

  • 如果s1 < s2,返回负数

  • 如果s1 == s2,返回0

  • 如果s1 > s2,返回正数

具体的数值取决于编译器:

#include <stdio.h> #include <string.h> void demonstrate_return_values() { printf("=== strcmp返回值实验 ===\n\n"); // 不同的编译器可能产生不同的具体数值 const char *s1 = "a"; // ASCII 97 const char *s2 = "b"; // ASCII 98 const char *s3 = "A"; // ASCII 65 int result1 = strcmp(s1, s2); int result2 = strcmp(s1, s3); printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s2, result1); printf("ASCII差值: 'a'(%d) - 'b'(%d) = %d\n\n", 'a', 'b', 'a' - 'b'); printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s3, result2); printf("ASCII差值: 'a'(%d) - 'A'(%d) = %d\n\n", 'a', 'A', 'a' - 'A'); // 常见误区:认为返回的是-1, 0, 1 printf("重要提醒:\n"); printf("strcmp不一定返回-1, 0, 1!\n"); printf("它只保证负/零/正。\n\n"); printf("if (strcmp(s1, s2) < 0) // 总是正确\n"); printf("if (strcmp(s1, s2) == 0) // 总是正确\n"); printf("if (strcmp(s1, s2) > 0) // 总是正确\n"); }

它只保证负/零/正

strcmp比较不同版本

版本1:
int simple_strcmp(const char *s1, const char *s2) { // 最基础的实现 while (*s1 && (*s1 == *s2)) { s1++; s2++; } return *(unsigned char*)s1 - *(unsigned char*)s2; }
版本2:
int detailed_strcmp(const char *s1, const char *s2) { // 步骤1:输入验证(标准strcmp不验证,但我们应该考虑) if (s1 == NULL || s2 == NULL) { // 标准行为:传入NULL是未定义的,可能导致崩溃 // 我们这里做安全处理 if (s1 == s2) return 0; // 两个都是NULL if (s1 == NULL) return -1; // NULL被认为小于任何字符串 if (s2 == NULL) return 1; // 任何字符串大于NULL } // 步骤2:逐字符比较 // 使用unsigned char*非常重要! // 原因:C语言的char可能是有符号的 // 比如,char值128会被当作-128处理 const unsigned char *p1 = (const unsigned char *)s1; const unsigned char *p2 = (const unsigned char *)s2; // 步骤3:循环直到发现不同或到达字符串结尾 while (*p1 && *p1 == *p2) { p1++; p2++; } // 步骤4:返回差值 // 当两个字符串相同时,*p1和*p2都是'\0',返回0 // 当发现不同时,返回两个字符的ASCII码差值 return *p1 - *p2; }

常见使用情况

1:排序比较
#include <stdio.h> #include <string.h> #include <stdlib.h> // 用于qsort的比较函数 int compare_strings(const void *a, const void *b) { const char **str1 = (const char **)a; const char **str2 = (const char **)b; return strcmp(*str1, *str2); } void sort_strings_demo() { const char *fruits[] = { "banana", "apple", "cherry", "date", "elderberry" }; int count = sizeof(fruits) / sizeof(fruits[0]); printf("排序前:\n"); for (int i = 0; i < count; i++) { printf("%d: %s\n", i, fruits[i]); } qsort(fruits, count, sizeof(char*), compare_strings); printf("\n排序后:\n"); for (int i = 0; i < count; i++) { printf("%d: %s\n", i, fruits[i]); } }
2:switch语句的替代
// strcmp不能直接用于switch,但可以这样处理 int handle_command(const char *cmd) { if (strcmp(cmd, "start") == 0) { return 1; } else if (strcmp(cmd, "stop") == 0) { return 2; } else if (strcmp(cmd, "pause") == 0) { return 3; } return 0;
3:常见错误
void common_mistakes() { // 错误1:误用返回值 char *s1 = "hello"; char *s2 = "world"; printf("误用返回值\n"); printf("if (strcmp(s1, s2)) { ... }\n"); printf("// 这实际检查的是:如果s1 != s2\n\n"); printf("明确检查\n"); printf("if (strcmp(s1, s2) == 0) { // 相等 }\n"); printf("if (strcmp(s1, s2) != 0) { // 不相等 }\n"); printf("if (strcmp(s1, s2) < 0) { // s1 < s2 }\n"); printf("if (strcmp(s1, s2) > 0) { // s1 > s2 }\n\n"); // 错误2:传递NULL指针 printf("传递NULL指针\n"); printf("strcmp(NULL, \"test\"); // 未定义行为,可能崩溃\n\n"); // 错误3:比较未初始化的字符串 char buffer[10]; printf("比较未初始化的字符串\n"); printf("char buffer[10];\n"); printf("strcmp(buffer, \"test\"); // 未定义行为\n\n"); }

strcmp的变体函数

strncmp:带长度限制的比较
void demonstrate_strncmp() { printf("=== strncmp演示 ===\n\n"); const char *s1 = "hello world"; const char *s2 = "hello there"; // 比较前5个字符 int result1 = strncmp(s1, s2, 5); printf("strncmp(\"%s\", \"%s\", 5) = %d\n", s1, s2, result1); printf("前5个字符相同:\"hello\"\n\n"); // 比较前6个字符 int result2 = strncmp(s1, s2, 6); printf("strncmp(\"%s\", \"%s\", 6) = %d\n", s1, s2, result2); printf("第6个字符不同:'w' vs 't'\n\n"); // 实际应用:比较固定前缀 const char *url = "https://example.com"; if (strncmp(url, "https://", 8) == 0) { printf("URL使用HTTPS协议\n"); } // 安全优势:避免缓冲区溢出 char user_input[10]; // 假设用户输入可能很长... const char *expected = "password"; // 安全比较,只比较前9个字符(包括'\0') if (strncmp(user_input, expected, sizeof(user_input)) == 0) { printf("密码匹配\n"); } }
strcasecmp:不区分大小写的比较
#include <strings.h> // 注意:不是string.h! #include <ctype.h> // 自定义实现(如果系统没有提供) int custom_strcasecmp(const char *s1, const char *s2) { if (s1 == s2) return 0; if (s1 == NULL) return -1; if (s2 == NULL) return 1; while (*s1 && *s2) { char c1 = tolower((unsigned char)*s1); char c2 = tolower((unsigned char)*s2); if (c1 != c2) { return c1 - c2; } s1++; s2++; } // 至少有一个字符串到达结尾 return tolower((unsigned char)*s1) - tolower((unsigned char)*s2); } void demonstrate_case_insensitive() { printf("=== 大小写不敏感比较 ===\n\n"); const char *names[] = { "alice", "Alice", "ALICE", "aLiCe", "bob", "Bob", "BOB" }; printf("区分大小写比较(strcmp):\n"); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { printf("strcmp(\"%s\", \"%s\") = %d\n", names[i], names[j], strcmp(names[i], names[j])); } } printf("\n不区分大小写比较:\n"); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { printf("strcasecmp(\"%s\", \"%s\") = %d\n", names[i], names[j], strcasecmp(names[i], names[j])); } } }
memcmp:内存比较(可处理含'\0'的数据)
void demonstrate_memcmp() { printf("=== memcmp vs strcmp ===\n\n"); // 情况1:二进制数据包含'\0' char data1[] = { 'H', 'e', 'l', 'l', 'o', '\0', 'W', 'o', 'r', 'l', 'd' }; char data2[] = { 'H', 'e', 'l', 'l', 'o', '\0', 'X', 'y', 'z' }; printf("数据包含'\\0'的情况:\n"); printf("strcmp会在第一个'\\0'处停止\n"); printf("memcmp会继续比较指定长度的所有字节\n\n"); // 比较前6个字节 printf("memcmp(data1, data2, 6) = %d\n", memcmp(data1, data2, 6)); printf("strcmp(data1, data2) = %d\n", strcmp(data1, data2)); // 比较前11个字节 printf("memcmp(data1, data2, 11) = %d\n", memcmp(data1, data2, 11)); // 实际应用:比较结构体 typedef struct { int id; char name[20]; float score; } Student; Student s1 = {1, "Alice", 95.5}; Student s2 = {1, "Alice", 95.5}; printf("\n结构体比较:\n"); printf("memcmp(&s1, &s2, sizeof(Student)) = %d\n", memcmp(&s1, &s2, sizeof(Student))); // 警告:memcmp可能因为内存对齐填充而失败 }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 6:50:33

5大核心特性解析:gumbo-parser纯C语言HTML5解析库的终极指南

5大核心特性解析&#xff1a;gumbo-parser纯C语言HTML5解析库的终极指南 【免费下载链接】gumbo-parser An HTML5 parsing library in pure C99 项目地址: https://gitcode.com/gh_mirrors/gum/gumbo-parser HTML5解析是现代Web开发中的关键技术环节&#xff0c;而gumbo…

作者头像 李华
网站建设 2026/5/26 6:18:02

SeedVR:扩散Transformer开启通用视频修复新范式

SeedVR&#xff1a;扩散Transformer开启通用视频修复新范式 【免费下载链接】SeedVR-7B 项目地址: https://ai.gitcode.com/hf_mirrors/ByteDance-Seed/SeedVR-7B 导语 字节跳动最新发布的SeedVR-7B模型&#xff0c;通过创新的扩散Transformer架构&#xff0c;突破了传…

作者头像 李华
网站建设 2026/5/26 6:49:56

Higress微服务流量治理:智能重试与熔断策略深度解析

Higress微服务流量治理&#xff1a;智能重试与熔断策略深度解析 【免费下载链接】higress Next-generation Cloud Native Gateway | 下一代云原生网关 项目地址: https://gitcode.com/GitHub_Trending/hi/higress 在当今复杂的微服务架构中&#xff0c;服务间的通信稳定…

作者头像 李华
网站建设 2026/5/25 10:34:03

Langchain-Chatchat监控告警系统集成:保障服务稳定性

Langchain-Chatchat监控告警系统集成&#xff1a;保障服务稳定性 在企业级 AI 应用日益普及的今天&#xff0c;本地知识库问答系统正成为数据敏感场景下的首选方案。Langchain-Chatchat 作为开源社区中“本地部署 大模型”架构的标杆项目&#xff0c;凭借其对私有文档的安全处…

作者头像 李华
网站建设 2026/5/26 6:50:34

3步搞定实时数据同步:Debezium实战避坑指南

3步搞定实时数据同步&#xff1a;Debezium实战避坑指南 【免费下载链接】debezium debezium/debezium: 是一个 Apache Kafka 的连接器&#xff0c;适合用于将 Kafka 的数据流式传输到各种数据库和目标中。 项目地址: https://gitcode.com/gh_mirrors/de/debezium 当数据…

作者头像 李华