news 2026/5/1 9:12:41

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/4/29 10:23:26

Langchain-Chatchat搜索关键词高亮显示实现

Langchain-Chatchat搜索关键词高亮显示实现 在企业知识管理日益智能化的今天&#xff0c;一个常见的挑战是&#xff1a;用户问了一个问题&#xff0c;系统返回了一段看似合理的答案&#xff0c;但没人知道这个答案是从哪来的。这种“黑箱式”输出虽然技术上可行&#xff0c;却…

作者头像 李华
网站建设 2026/5/1 5:07:33

Langchain-Chatchat Swagger集成步骤详解

Langchain-Chatchat Swagger集成深度实践 在企业级AI应用日益普及的今天&#xff0c;如何在保障数据安全的前提下&#xff0c;高效构建可维护、易集成的智能问答系统&#xff0c;成为许多技术团队面临的现实挑战。尤其当业务涉及敏感文档——如内部制度、客户合同或研发资料时&…

作者头像 李华
网站建设 2026/4/30 22:21:51

Langchain-Chatchat意图识别模块优化方向

Langchain-Chatchat意图识别模块优化方向 在企业级智能问答系统日益普及的今天&#xff0c;如何让AI真正“听懂”用户的问题&#xff0c;成为决定用户体验的关键。尤其是在金融、医疗、法律等对数据安全要求极高的行业&#xff0c;基于本地知识库的解决方案正逐步替代传统云端助…

作者头像 李华
网站建设 2026/4/30 18:47:36

31、数据仓库与 OLAP 技术全面解析

数据仓库与 OLAP 技术全面解析 1. 数据架构基础 在数据处理架构中,互联网用户连接到 Web 服务器,而 Web 服务器连接到分析服务器立方体(cube)。这种架构能让用户无论身处何地都能访问立方体数据,还方便了以往难以实现的 Web 界面数据分析与报告。 交易处理数据库和分析…

作者头像 李华
网站建设 2026/5/1 8:43:03

FastAPI语音识别终极指南:快速构建高性能音频转录API

FastAPI语音识别终极指南&#xff1a;快速构建高性能音频转录API 【免费下载链接】awesome-fastapi A curated list of awesome things related to FastAPI 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-fastapi 想要快速构建高性能的语音识别API吗&#xff1f…

作者头像 李华
网站建设 2026/5/1 5:03:03

影院购票系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】

摘要 随着互联网技术的快速发展和人们生活水平的提高&#xff0c;影院观影已成为大众娱乐的重要方式之一。传统影院购票方式存在排队时间长、座位选择不便、信息更新滞后等问题&#xff0c;影响了用户体验和影院运营效率。为优化购票流程、提升管理效能&#xff0c;设计并实现一…

作者头像 李华