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博客