当前位置: 首页 > news >正文

字符串比较函数strcmp和strncmp以及memcmp详解与对比分析

字符串比较函数strcmp和strncmp详解

  • C语言字符串与内存比较函数详解:strcmp、strncmp与memcmp对比分析
    • 使用场景指南
    • 性能与安全注意事项
      • 返回值陷阱
      • 跨平台风险
      • 安全比较实践
    • 总结选择策略
  • 不要用memcmp比较结构体
    • C++关于使用memcmp判断结构体是否相等的隐患问题
  • Chapter1 字符串比较函数strcmp和strncmp详解
    • 一、函数简介
    • 二、函数原型与参数解析
      • 2.1 strcmp () 原型
      • 2.2 strncmp () 原型
    • 三、函数实现逻辑
      • 3.1 strcmp () 伪代码实现
      • 3.2 strncmp () 伪代码实现
    • 四、典型使用场景:何时用 strcmp (),何时用 strncmp ()
      • 4.1 strcmp () 的适用场景
      • 4.2 strncmp () 的适用场景
    • 五、关键注意事项
      • 5.1 strcmp () 必须依赖 '\0',否则越界
      • 5.2 strncmp () 的 n 是无符号整数,不可传负数
      • 5.3 返回值不是只有 - 1、0、1
      • 5.4 不可比较多字节字符串(如中文)
      • 5.5 避免传入 NULL 指针
    • 六、函数差异对比:一张表看懂核心区别
    • 七、完整示例代码:综合场景实践


C语言字符串与内存比较函数详解:strcmp、strncmp与memcmp对比分析

原文链接:https://blog.csdn.net/m0_37989557/article/details/149144189

在这里插入图片描述

在 C 语言开发中,字符串比较是高频操作 —— 从用户名密码验证、配置项匹配,到数据排序与查找,都离不开字符串比较函数。C 标准库<string.h>提供的strcmp()与strncmp()是最常用的两个工具,但开发者常因混淆两者的适用场景、忽略边界条件导致 bug(如缓冲区越界、比较结果异常)。

使用场景指南

优先使用 strcmp:

  • 比较用户输入的字符串命令

  • 排序纯文本数据

if (strcmp(input, "quit") == 0) exit(0);

优先使用 strncmp:

  • 检查协议前缀(如 HTTP/FTP)

  • 比较定长字符串标识符

// 检测HTTP请求
if (strncmp(request, "GET ", 4) == 0) {...}

优先使用 memcmp:

  • 验证数据结构完整性

  • 比较加密哈希值

  • 处理二进制文件格式

// 校验数据副本
memcmp(original, backup, sizeof(DataStruct));

性能与安全注意事项

返回值陷阱

// 错误用法:假设返回1/-1
if (strcmp(a, b) == 1)  // 不可靠!可能返回任意正数// 正确用法
if (strcmp(a, b) > 0)   // 检查符号而非具体值

跨平台风险

// 结构体比较可能因填充字节失败
struct Data { char c; int i; }; // 可能有3字节填充
memcmp(&d1, &d2, sizeof(struct Data)); // 结果可能不一致// 不同平台 内存填充布局和填充数量可能不一致;这样相同代码运行在不同平台,得出的结果可能不一致

安全比较实践

// 敏感数据比较(防时序攻击)
// 以下代码可避免。不做详细分析
int secure_compare(const void *a, const void *b, size_t len) {const uint8_t *pa = a;const uint8_t *pb = b;uint8_t diff = 0;for (size_t i = 0; i < len; i++) {diff |= pa[i] ^ pb[i];}return diff;
}// 时序攻击是一种侧信道攻击(Side-channel attack),
// 攻击者通过测量比较操作的执行时间差异来推断敏感数据的内容。在安全系统中,这种攻击尤其危险:
// 利用的是memcmp函数的漏洞,
// 漏洞原理:
// 比较不同位置所需时间不同:
//     第一个字节不同 → 快速返回
//     最后一个字节不同 → 慢速返回
// 攻击者可测量响应时间模式:逐个分析确定敏感数据,如密码

总结选择策略

在这里插入图片描述

不要用memcmp比较结构体

原文链接

除非在项目中可以保证所有的结构体都会使用memset来进行初始化(这个是很难保证的) , 否则就不要直接使用memcmp来比较结构体。

C++关于使用memcmp判断结构体是否相等的隐患问题

原文链接

结构体struct
C++除了除了比较高级的class之外,还有跟他很像的struct,但是如何比较两个结构体是否相等呢(结构体的每个变量都相等),这时候很容易想到了c里面的memcmp函数。
经检验,在使用memcmp比较结构体的时候,有个问题:有时候明明两个结构体的所有变量都是一样的,返回的还是非0。

找到原因
找了很多博客之后,都说和字节对齐有关,之前看过字节对齐,还是不懂为什么。
后来才知道,字节对齐的机制会给结构体填充一些不用的空间,这些空间的内容是随机的,也就是说,如果结构体里面有字节对齐填充的操作了,那么memcmp就不能达到效果。

Chapter1 字符串比较函数strcmp和strncmp详解

原文链接:https://blog.csdn.net/weixin_37800531/article/details/141977891

一、函数简介

字符串比较的本质是按 ASCII 码值逐字符对比,而非比较字符串长度。C 语言中字符串以’\0’作为结束标志,这一特性直接决定了strcmp()与strncmp()的设计逻辑差异:
在这里插入图片描述
简单来说:strcmp()是 “全自动” 比较(直到结束符),strncmp()是 “半自动” 比较(指定最大长度)。两者的返回值逻辑一致 —— 均通过字符 ASCII 差值判断大小,但适用场景和安全性差异显著。

二、函数原型与参数解析

要正确使用函数,首先需理解其原型定义(来自<string.h>头文件),尤其是参数的约束与含义。

2.1 strcmp () 原型

int strcmp(const char *str1, const char *str2);

参数说明:

str1/str2:待比较的两个字符串指针(const修饰表示函数不会修改输入字符串,避免误操作);
要求:两个字符串必须以’\0’结尾(否则会触发越界)。

返回值:int 类型,代表比较结果:

返回0:str1与str2内容完全相同;
返回正数:str1中第一个不同字符的 ASCII 值 > str2对应字符;
返回负数:str1中第一个不同字符的 ASCII 值 < str2对应字符。

2.2 strncmp () 原型

int strncmp(const char *str1, const char *str2, size_t n);

参数说明:

前两个参数与strcmp()一致;
n:最大比较字符数(size_t是无符号整数类型,取值≥0);
优势:无需强制要求字符串以’\0’结尾(若n小于字符串长度,会提前终止)。

返回值:逻辑与strcmp()完全一致,仅比较范围受n限制:

若前n个字符完全相同,无论后续内容如何,均返回0;
若未比较到n个字符时已出现不同,返回第一个不同字符的 ASCII 差值。

三、函数实现逻辑

理解函数的实现逻辑,能帮你规避 90% 的使用错误。以下伪代码基于 C 标准(ISO/IEC 9899)的规范,还原了两个函数的核心执行流程(非编译器真实实现,但逻辑一致)。

3.1 strcmp () 伪代码实现

// 功能:比较str1和str2,直到'\0'或不同字符
function strcmp(const char* str1, const char* str2) -> int:// 1. 校验指针合法性(真实库函数可能不校验,直接触发段错误)if str1 == NULL or str2 == NULL:触发未定义行为(如程序崩溃)// 2. 逐字符比较(直到'\0'或不同)while *str1 != '\0' and *str2 != '\0':if *str1 != *str2:// 返回当前字符ASCII差值(str1 - str2)return (unsigned char)*str1 - (unsigned char)*str2// 指针向后移动str1 = str1 + 1str2 = str2 + 1// 3. 处理一方已到'\0'的情况(如"abc" vs "abcd")return (unsigned char)*str1 - (unsigned char)*str2
  • 用unsigned char转换字符:避免 ASCII 码中负数(如扩展 ASCII 的 0x80-0xFF)导致的比较错误;
  • 终止条件:必须同时满足 “字符相同” 且 “未到 ‘\0’”,否则退出循环;
  • 最终差值:若一方先到 ‘\0’(如"a" vs “aa”),则*str1为 ‘\0’(ASCII 0),*str2为 ‘a’(ASCII 97),返回 - 97。

3.2 strncmp () 伪代码实现

// 功能:比较str1和str2的前n个字符,或到'\0'
function strncmp(const char* str1, const char* str2, size_t n) -> int:// 1. 校验指针合法性if str1 == NULL or str2 == NULL:触发未定义行为// 2. 逐字符比较(直到n=0、字符不同或'\0')while n > 0 and *str1 != '\0' and *str2 != '\0':if *str1 != *str2:return (unsigned char)*str1 - (unsigned char)*str2// 指针移动 + 计数递减str1 = str1 + 1str2 = str2 + 1n = n - 1// 3. 处理三种终止情况:n=0、str1到'\0'、str2到'\0'if n == 0:// 已比较完n个字符,视为相同return 0else:// 一方到'\0',返回差值(同strcmp)return (unsigned char)*str1 - (unsigned char)*str2
  • n的优先级最高:即使字符未到’\0’,只要n减至 0,立即返回 0;
  • 无’\0’安全:若字符串无结束符(如数组存储的固定长度数据),只要n设置为数组长度,就不会越界。

四、典型使用场景:何时用 strcmp (),何时用 strncmp ()

选择函数的核心依据是是否需要完整比较与是否确定字符串有 ‘\0’ ,以下是两类函数的典型应用场景。

4.1 strcmp () 的适用场景

当满足 “字符串以’\0’结尾” 且 “需比较完整内容” 时,优先用strcmp(),代码更简洁。

场景 1:用户名 / 密码验证

用户输入的字符串(如密码)通常以’\0’结尾,需完整匹配才能通过验证:

#include <stdio.h>
#include <string.h>#define CORRECT_USER "admin"
#define CORRECT_PWD "Secure@2025"// 验证用户名密码
int auth_user(const char* input_user, const char* input_pwd) {// 用户名和密码必须都完整匹配if (strcmp(input_user, CORRECT_USER) == 0 && strcmp(input_pwd, CORRECT_PWD) == 0) {return 1; // 验证通过}return 0; // 验证失败
}int main() {char input_user[32], input_pwd[32];printf("请输入用户名:");scanf("%s", input_user);printf("请输入密码:");scanf("%s", input_pwd);if (auth_user(input_user, input_pwd)) {printf("登录成功!\n");} else {printf("用户名或密码错误!\n");}return 0;
}

运行结果:

输入admin和Secure@2025 → 登录成功;
输入admin和Secure@2024 → 密码错误。

场景 2:判断文件后缀名

文件路径字符串以’\0’结尾,需完整匹配后缀名(如.txt):

// 判断文件是否为txt格式
int is_txt_file(const char* file_path) {// 找到最后一个'.'的位置const char* dot = strrchr(file_path, '.');if (dot == NULL) {return 0; // 无后缀名}// 完整比较后缀名是否为".txt"return strcmp(dot, ".txt") == 0;
}

4.2 strncmp () 的适用场景

当需要 “部分比较” 或 “字符串无’\0’” 时,必须用strncmp(),避免越界风险。

场景 1:判断字符串前缀

如判断 URL 是否为 HTTP/HTTPS 协议(只需比较前 7 个字符"http://“或前 8 个"https://”):

#include <stdio.h>
#include <string.h>// 判断URL是否为HTTP/HTTPS协议
int is_http_proto(const char* url) {if (url == NULL) return 0;// 比较前7个字符(http://)或前8个(https://)return strncmp(url, "http://", 7) == 0 || strncmp(url, "https://", 8) == 0;
}int main() {char urls[][64] = {"http://blog.example.com","https://github.com","ftp://file.example.net","https://127.0.0.1:8080"};for (int i = 0; i < 4; i++) {if (is_http_proto(urls[i])) {printf("[%s] 是HTTP/HTTPS协议\n", urls[i]);} else {printf("[%s] 非HTTP/HTTPS协议\n", urls[i]);}}return 0;
}

运行结果:
在这里插入图片描述
场景 2:固定长度字段比较

硬件通信、数据库存储中,常以固定长度数组存储字符串(无’\0’),需指定长度比较:

运行结果:
在这里插入图片描述

五、关键注意事项

strcmp()与strncmp()的很多 bug 源于忽略细节,以下是必须牢记的 5 个注意事项。

5.1 strcmp () 必须依赖 ‘\0’,否则越界

strcmp()会一直遍历内存直到’\0’,若字符串无结束符,会触发缓冲区越界访问(未定义行为):

解决方法:

  • 定义数组时预留’\0’位置:char str1[4] = {‘a’,‘b’,‘c’,‘\0’};
  • 用strncmp()指定长度:strncmp(str1, str2, 3)。

5.2 strncmp () 的 n 是无符号整数,不可传负数

n的类型是size_t(无符号),若传入负数,会被强制转换为极大的正数(如 - 1→4294967295),导致越界:

#include <stdio.h>
#include <string.h>int main() {char str1[] = "abc";char str2[] = "abd";int n = -1; // 错误:负数转换为size_t最大值// 风险:比较4294967295个字符,必然越界int result = strncmp(str1, str2, n);printf("结果:%d\n", result);return 0;
}

解决方法:

确保n是非负数:用n = (n < 0) ? 0 : n做防御;
用sizeof()获取固定长度:如strncmp(str1, str2, sizeof(str1)-1)(减 1 是预留’\0’位置)。

5.3 返回值不是只有 - 1、0、1

C 标准仅规定返回值的符号(正 / 负 / 零),未规定具体数值。不同编译器实现可能返回 “第一个不同字符的 ASCII 差值”:

#include <stdio.h>
#include <string.h>int main() {// 'a' ASCII=97,'c'=99 → 差值为-2printf("strcmp(\"a\", \"c\") = %d\n", strcmp("a", "c")); // 'x'=120,'m'=109 → 差值为11printf("strcmp(\"x\", \"m\") = %d\n", strcmp("x", "m")); return 0;
}

GCC 编译器运行结果:

strcmp("a", "c") = -2
strcmp("x", "m") = 11

错误写法:if (strcmp(a, b) == -1) → 某些编译器可能返回 - 2,导致判断失效;

正确写法:if (strcmp(a, b) < 0)。

5.4 不可比较多字节字符串(如中文)

strcmp()与strncmp()均按单字节 ASCII 码比较,而中文(如 GBK、UTF-8)是多字节编码,比较结果会出错:

#include <stdio.h>
#include <string.h>int main() {// UTF-8中,"中"占3字节,"国"占3字节char str1[] = "中";char str2[] = "国";// 错误:比较的是第一个字节的ASCII值,而非汉字本身int result = strcmp(str1, str2);printf("strcmp(\"中\", \"国\") = %d\n", result); return 0;
}

运行结果:strcmp(“中”, “国”) = -32(无实际意义)

解决方法:使用宽字符函数wcscmp()(比较wchar_t类型字符串)或专门的多字节比较库(如iconv)。

5.5 避免传入 NULL 指针

两个函数均未处理NULL参数,传入NULL会触发段错误(程序崩溃):

#include <string.h>int main() {// 错误:str2为NULL,触发段错误strcmp("abc", NULL); return 0;
}

解决方法:加指针合法性校验:

int safe_strcmp(const char* a, const char* b) {if (a == NULL && b == NULL) return 0;   // 两者都为NULL,视为相等if (a == NULL) return -1;               // a为NULL,视为小于bif (b == NULL) return 1;                // b为NULL,视为小于areturn strcmp(a, b);
}

六、函数差异对比:一张表看懂核心区别

为方便快速查阅,以下表格总结了strcmp()与strncmp()的关键差异:
在这里插入图片描述

七、完整示例代码:综合场景实践

以下示例结合文件后缀判断(strcmp())与 URL 前缀判断(strncmp()),展示两个函数的协同使用:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>// 1. 用strcmp()判断文件是否为图片(.jpg/.png)
bool is_image_file(const char* file_path) {if (file_path == NULL) return false;const char* dot = strrchr(file_path, '.');if (dot == NULL) return false;return strcmp(dot, ".jpg") == 0 || strcmp(dot, ".png") == 0;
}// 2. 用strncmp()判断URL是否为HTTPS(需比较前8个字符)
bool is_https_url(const char* url) {if (url == NULL) return false;// 确保URL长度≥8,避免n超过字符串长度(可选防御)if (strlen(url) < 8) return false;return strncmp(url, "https://", 8) == 0;
}// 3. 综合判断:是否为HTTPS链接的图片文件
bool is_https_image(const char* https_url) {return is_https_url(https_url) && is_image_file(https_url);
}int main() {char test_urls[][128] = {"https://blog.example.com/photo1.jpg","http://example.com/photo2.png","https://img.example.net/logo.svg","ftp://file.example.com/doc.pdf","https://example.com/avatar.jpg"};printf("=== HTTPS图片链接检测结果 ===\n");for (int i = 0; i < 5; i++) {const char* url = test_urls[i];if (is_https_image(url)) {printf("[√] %s → 是HTTPS图片链接\n", url);} else {printf("[×] %s → 不是HTTPS图片链接\n", url);}}return 0;
}

运行结果:
在这里插入图片描述
strcmp()与strncmp()是 C 语言字符串操作的基础工具,两者的核心差异在于 “是否控制比较范围”。实际开发中,需根据 “是否有’\0’” 和 “是否需完整比较” 选择函数 —— 不确定场景下,strncmp()的安全性更高(只要n设置合理)。掌握本文的实现逻辑、注意事项与场景选择原则,能帮你避免 90% 以上的字符串比较 bug,写出更健壮的 C 语言代码。

http://www.dtcms.com/a/454124.html

相关文章:

  • linux练习-2
  • 大连做网站首选领超科技35互联做的网站
  • 国庆科技感祝福:Python 粒子国旗动画
  • 厦门微信网站开发潮州汕头
  • SSH隧道技术详解:从本地端口转发到实战应用
  • 西宁微网站建设电商网名大全
  • 网站多少钱一米无锡市住房建设局网站
  • 做自己网站做站长女的和男的做那个视频网站
  • 东莞网站维护wordpress调用分类链接
  • 贵阳网站建设包首页钦州建站哪家好
  • excel 表格 做的网站wordpress+qq音乐插件
  • 安阳七彩祥云网络公司seo人员的职责
  • k8s面试题
  • 齐齐哈尔建设局网站中卫 网红打卡地
  • 【完整源码+数据集+部署教程】 水道图像分割系统: yolov8-seg-EfficientHead
  • 做手机网站用什么网站互动性
  • 南宁市做公司网站个人工作室和公司的区别
  • 2019历年-英语
  • 电子商务网站建设与规划wordpress 后台 404
  • Blender弹珠轨道场景动画资产预设 Marble Run Kit V4.1.9
  • AI编程开发系统022-基于Vue+SpringBoot的智能家居系统(源码+部署说明+演示视频+源码介绍+lw)
  • 动力 网站建设东莞建网站公司案例
  • Spring WebFlux 原理与实践全解析
  • 网站建设学生作业成品如何做外文网站
  • 中学网站源码展示页网站怎么做排名
  • 江苏省建设工程协会网站外贸网站推广建站
  • 【C++】运算符替代写法全解析
  • 广州建设网站哪家好支付招聘网站怎么做费用
  • 免费扑克网站代码商城网站建设一般需要多少钱
  • kanass入门到实战(10) - 如何做好测试管理?