C语言函数:字符串函数及模拟实现strcmp()

news2024/11/19 17:26:26

C语言函数:字符串函数及模拟实现strcmp()

strcmp()函数:

        作用:进行字符串的比较大小。

引入:如下代码,

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main()
{
	char* p = "wan";
	char* q = "ban";
	if (p > q)
		printf(">");
	else if ("abc" > "abeiqeaf")
		printf(">=");
	//这两种方法比较的都是字符串首元素地址,而不是字符串的ASCLL值
	else
		printf("<");
	return 0;
}

        这两种方法比较的都是字符串首元素地址,而不是字符串大小

        因此,如果要比较两个字符串大小,那么就需要用到strcmp()函数。

        原理:依次比较两个字符串的ASCII码值,第一个和第一个比、第二个和第二个比。。。

        如上图p和q比较:'w'和'b'比较ASCII码值,w比'b'大。如此p就比q大,不会再看后面的字符串,无论这个q有多少个字符。

        如上图"abc"和"abeiqeaf"比较:'a'比较'a',ASCII码值相同,然后会一起跳到下一个字符,再比较'b''和'b',ASCII码值相同,然后会一起跳到下一个字符,再比较'c''和'e',ASCII不同,那么"abc"就比"abeiqeaf"大。

        如果一样,如"ab"和"ab",strcmp当遇到\0时就会停止,最后这两个字符串相同

        前面看到,strcmp返回值是int类型,这也是为什么strcmp是用来比较大小的关键。

        

         strcmp返回值有三个可能:-1(<0)、0(=0)、1(>0)。

        <0 说明第一个字符串比第二个字符串小。

        =0 说明第一个字符串和第二个字符串一样。

        >0 说明第一个字符串比第二个字符串大。

        

<0:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main()
{
	printf("%d\n",strcmp("abc","abp"));
	//结果: -1
	return 0;
}

=0:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main()
{
	printf("%d\n",strcmp("abc","aba"));
	//结果: 1
	return 0;
}

>0:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main()
{
	printf("%d\n",strcmp("abc","abc"));
	//结果: 0
	return 0;
}

strcmp()函数的模拟实现:

第一种:

 与strcmp原理如出一辙

        s1和s2是否相同,相同则继续寻找,当找到\0时停止

        s1和s2不同,判断s1和s2大小,s1>s2返回1,反之返回0。

第二种:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int my_strcmp(const char* str1, const char* str2)
{
	int ret = 0;

	while ((ret = *(unsigned char*)str1 - *(unsigned char*)str2) == 0 && *str2)
	{
		++str1, ++str2;
	}

	return ((-ret) < 0) - (ret < 0);
}

int main()
{
	char* p = "a";
	char* q = "a";
	int ret = my_strcmp(p, q);
	if (ret > 0)
		printf("p>q\n");
	else if (ret < 0)
		printf("p<q\n");
	else
		printf("p==q\n");
	return 0;
}

        这里面的my_strcmp的实现,是和库函数内的strcmp是一样的。

        首先看到,while循环,当两个相减等于0并且其中一个不等于\0时,找下一个。

        因为,strcmp实际是比较两个字符串字符相同,既然如此,只需要知道其中一个字符串是不是\0就行,因为如果两个字符串相同,那么长度肯定是一样的,\0的位置就一定一样,如果,其中一个先找到\0或者后找到\0,那么长度肯定不同。因此,只需要找到其中一个不等于\0就行。

        当其中有不同的字符或全部相同时,结束while循环,其中不同的字符包括用\0比较的。
 

        

        return ((-ret) < 0) - (-ret) < 0);这是整段代码的核心,也是最难理解的:

        (-ret) < 0和ret < 0都是比较大小,因此结果肯定是:0或1

        0表示这个表达式不成立,1表示这个表达式成立

        首先是两个都是\0,那么都是0,表达式是0-0=0,则返回0,表示两个字符串相同

        (-ret) < 0如果结果是0说明-----(-ret)>0说明------ret<0(第一个肯定比第二个小)第二个表达式就为1----------0-1结果为:-1

        (-ret) < 0如果结果是1说明-----(-ret)<0说明------ret>0(第一个肯定比第二个大)第二个表达式就为0----------1-0结果为:1

        想必你肯定还是不懂,那就看看下面推导出这个表达式的思路把。

        

得到 return ((-ret) < 0) - (-ret) < 0)的思路:

        既然要返回-1,0,1这三个数,那么这三个数都可以通过0-1,0-0,1-0表示。发现0和1是二进制,就可以想到表达式是否成立的值就是0和1,这两个值的结合就可以完成输出,-1、0、1这三个结果。那么就是怎么组合表达式,使得这个表达式能够输出这三个结果呢? 

        之后发现,如果ret给的负数,就要创建一个表达式让这个表达式的结果为-1,那么就知道第一个肯定比第二个小,-1就可以用0-1表示。试试ret<0这个表达式的结果应该是1,1得到了就差前面的0了,0怎么得到呢?ret>0?那就是ret>0 - ret<0? 

        最后发现ret无论等于负数还是正数,都可以无误地输出-1,0,1这三个结果。代码都是探索出来的。是的,ret>0 - ret<0的确可以,只不过strcmp的作者把前面ret加了-号,学过数学都知道,两边同乘-数,符号方向改变。所以:(-ret) < 0 等同于 (ret > 0),所以(ret>0) - (ret<0)到最后变成了(-ret) < 0) - (-ret) < 0,这样确实是降低了代码的可读性。

        可以了解一下strncmp():

kC语言函数:字符串函数及模拟实现strncpy()、strncat()、strncmp()_srhqwe的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/388405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring MVC源码解析——HandlerMapping(处理器映射器)

Sping MVC 源码解析——HandlerMapping处理器映射器1. 什么是HandlerMapping2. HandlerMapping2.1 HandlerMapping初始化2.2 getHandler解析3. getHandlerInternal()子类实现3.1 AbstractUrlHandlerMapping与AbstractHandlerMethodMapping的区别3.2 AbstractUrlHandlerMapping3…

MySQL实战解析底层---全局锁和表锁:给表加个字段怎么有这么多阻碍

目录 前言 全局锁 表级锁 前言 数据库锁设计的初衷是处理并发问题作为多用户共享的资源&#xff0c;当出现并发访问的时候&#xff0c;数据库需要合理地控制资源的访问规则而锁就是用来实现这些访问规则的重要数据结构根据加锁的范围&#xff0c;MySQL 里面的锁大致可以分成…

js正则表达式以及元字符

0、常用的正则表达式规则 手机号 const reg /^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\d{8}$/;密码 const reg /^[a-zA-Z0-9]{6,20}$/;验证码 const reg /^\d{6}$/;1、正则表达式的介绍与使用 正则表达式(Regular Expression)是用于匹配字符串中字符组合…

RTOS中信号量的实现与应用

RTOS中的信号量是一种用来协调多个任务间共享资源访问的同步机制。它可以保证多个任务之间访问共享资源的正确性和一致性&#xff0c;避免了因多任务并发访问造成的不可预期的问题。 信号量的实现 信号量的实现原理比较简单&#xff0c;主要包括两个部分&#xff1a;计数器和…

12 readdir 函数

前言 在之前 ls 命令 中我们可以看到, ls 命令的执行也是依赖于 opendir, readdir, stat, lstat 等相关操作系统提供的相关系统调用来处理业务 因此 我们这里来进一步看一下 更细节的这些 系统调用 我们这里关注的是 readdir 这个函数, 入口系统调用是 getdents 如下调试…

HDMI协议介绍(六)--EDID

目录 什么是EDID EDID结构 1)Header Information 头信息(厂商信息、EDID 版本等) (2)Basic Display Parameters and Features 基本显示参数(数字/模拟接口、屏幕尺寸、格式支持等) (3)色度信息 (4)Established Timings(VESA 定义的电脑使用 Timings) (5)Standard Timing…

并发编程——synchronized优化原理

如果有兴趣了解更多相关内容&#xff0c;欢迎来我的个人网站看看&#xff1a;耶瞳空间 一&#xff1a;基本概念 使用synchronized实现线程同步&#xff0c;即加锁&#xff0c;实现的是悲观锁。加锁可以使一段代码在同一时间只有一个线程可以访问&#xff0c;在增加安全性的同…

Python基础知识——字符串、字典

字符串 在Python中&#xff0c;字符和字符串没有区别。可能有些同学学过其他的语言&#xff0c;例如Java&#xff0c;在Java中&#xff0c;单引号’a’表示字符’a’&#xff0c;双引号"abc"表示字符串"abc"&#xff0c;但在Python当中&#xff0c;它们没…

【百日百题-C语言-1】KY15、45、59、72、101、132

本节目录1、KY15 abc2、KY45 skew数3、KY59 神奇的口袋4、KY72 Digital Roots5、KY115 后缀子串排序6、KY132 xxx定律 3n1思想7、KY168 字符串内排序1、KY15 abc #include<stdio.h> int main() {int a,b,c;for(a1;a<9;a)for(b1;b<9;b)for(c0;c<9;c){int xa*100 …

【macOS软件】iThoughtsX 9.3 思维导图软件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。应用介绍iThoughtsX可以帮助您直观组织想法、主意和信息。亮点使用大部分常用桌面应用程序格式来进行导入导出MindManageriMindmapFreemind/FreeplaneNovamindXMindMindviewConceptDrawOPML (OmniOutliner, Scrivener etc.)…

CornerNet介绍

CornerNet: Detecting Objects as Paired Keypoints ECCV 2018 Paper&#xff1a;https://arxiv.org/pdf/1808.01244v2.pdf Code&#xff1a;GitHub - princeton-vl/CornerNet 摘要&#xff1a; 提出了一种single-stage的目标检测算法CornerNet&#xff0c;它把每个目标检…

Vector - CAPL - 获取相对时间函数

在自动化开发中&#xff0c;无论是CAN通信测试&#xff0c;还是网络管理测试&#xff0c;亦或是休眠唤醒等等存在时间相关的&#xff0c;都可能会使用相关的时间函数&#xff1b;今天主要介绍的就是获取当前时间&#xff0c;我们知道vector工具的最大优势就是稳定和精确度高&am…

Windows使用QEMU搭建arm64 ubuntu 环境

1. 下载 QEMU&#xff1a; https://qemu.weilnetz.de/w64/ QEMU UEFI固件文件&#xff1a; https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/QEMU_EFI.fd arm64 Ubuntu镜像&#xff1a; http://cdimage.ubuntu.com/releases/20.04.3/rel…

docker-compsoe启动nginx

本次采用的是nginx:1.20版本 下载命令 docker pull nginx:1.20docker-compose.yml version: 3 services: nginx:restart: always image: nginx:1.20container_name: nginx1.20ports:- 80:80volumes: - /home/nginx-docker/nginx.conf:/etc/nginx/nginx.conf- /home/nginx-do…

【mysql是怎样运行的】-InnoDB数据页结构

文章目录1. 数据库的存储结构&#xff1a;页1.1 磁盘与内存交互基本单位&#xff1a;页1.2 页结构概述1.3 页的上层结构2. 页的内部结构2.1 第1部分&#xff1a;文件头部和文件尾部2.1.1 File Header&#xff08;文件头部&#xff09;&#xff08;38字节&#xff09;2.1.2 File…

时序预测 | MATLAB实现IWOA-BiLSTM和BiLSTM时间序列预测(改进的鲸鱼算法优化双向长短期记忆神经网络)

时序预测 | MATLAB实现IWOA-BiLSTM和BiLSTM时间序列预测(改进的鲸鱼算法优化双向长短期记忆神经网络) 目录时序预测 | MATLAB实现IWOA-BiLSTM和BiLSTM时间序列预测(改进的鲸鱼算法优化双向长短期记忆神经网络)预测效果基本介绍程序设计参考资料预测效果 基本介绍 MATLAB实现IWO…

[1.3_3]计算机系统概述——系统调用

文章目录第一章 计算机系统概述系统调用&#xff08;一&#xff09;什么是系统调用&#xff0c;有何作用&#xff08;二&#xff09;系统调用与库函数的区别&#xff08;三&#xff09;小例子&#xff1a;为什么系统调用是必须的&#xff08;四&#xff09;什么功能要用到系统调…

Spring——整合junit4、junit5使用方法

spring需要创建spring容器&#xff0c;每次创建容器单元测试是测试单元代码junit4依赖<?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-i…

【mysql是怎样运行的】-InnoDB行格式

文章目录1 指定行格式的语法2 COMPACT行格式2.1 变长字段长度列表2.2 NULL值列表2.3 记录头信息&#xff08;5字节&#xff09;2.4 记录的真实数据3 Dynamic和Compressed行格式1 指定行格式的语法 CREATE TABLE 表名 (列的信息) ROW_FORMAT行格式名称ALTER TABLE 表名 ROW_FOR…

Java面试题总结

文章目录前言1、JDK1.8 的新特性有哪些&#xff1f;2、JDK 和 JRE 有什么区别&#xff1f;3、String&#xff0c;StringBuilder&#xff0c;StringBuffer 三者的区别&#xff1f;4、为什么 String 拼接的效率低&#xff1f;5、ArrayList 和 LinkedList 有哪些区别&#xff1f;6…