c语言 - 为什么使用 !strcmp 而不是 strcmp



在这里,我写了一个代码来找出一个单词是否可用。

#include <stdio.h>
#include <string.h>
char *names[] = {"Sushant", "Jhon", "Robin", "Mark", NULL};
int search(char *p[], char *names);
int main(void){
if(search(names, "Sushant") != -1){
printf("Sushant is in this list");
} else{
printf("Sushant is not in this list.");
}
return 0;
}
int search(char *p[], char *name){
register int t;
for(t = 0; p[t]; t++){
if(!strcmp(p[t], name)){
return t;
} else{
return -1;
}
}
}

代码工作正常。但问题是。为什么它有效?我正在使用strcmp来比较数组和给定名称,但我也在strcmp开头使用!来反转语句。问题是应该只有strcmp而不是!strcmp你能告诉我为什么在这里使用!strcmp吗?

为什么使用 !strcmp 而不是 strcmp?

这是一个糟糕的成语。 我们可以争论贫穷是使用成语的人的错,还是以这种方式设计strcmp的人的错,从而激发了使用(穷人)成语。

当然,有些函数是"布尔值"的:它们返回真/假值。 其他的,如getcharsqrt,绝对不是:非布尔函数可以返回整个范围的值。 所以这里的关键问题是,strcmp布尔函数吗? 一个重要的次要问题是,strcmp的名字是否准确地反映了它的布尔或非布尔状态?

当然,strcmp不是二进制的。 它可以返回 3 个值:负、零或正,具体取决于第一个字符串在字典顺序上是小于、等于还是大于第二个字符串。 此外,正如我刚才所说,如果两个字符串相等strcmp返回 0。

现在,想要编写一个if()语句,如果两个字符串相等,则执行某些操作是很常见的。 字符串在 C 中是二等公民,所以你不会将它们与==进行比较,你将不得不调用一个函数。 所以你要写一些类似的东西

if(f(string1, string1))

因此,如果您确实有一个返回布尔值的字符串比较函数,则可以编写类似

if(strings_are_equal(string1, string2))

或者,也许,你可以或多或少地等价地写一些类似的东西

if(!strings_are_different(string1, string2))

但是您没有布尔值字符串比较函数,至少在标准 C 库中没有。 你有strcmp,它不仅告诉您字符串是否相同,它还告诉您(如果它们不同)哪个更大。 这应该是一种帮助,但它最终激励了你问的可怜的成语。

由于如果字符串相等,则返回strcmp0,并且由于 0 在 C 中是"false",因此许多程序员发现你可以写

if(!strcmp(string1, string2))

它有效。 正如您会注意到的,这实际上与假设的代码相同

if(!strings_are_different(string1, string2))

我之前建议过。 唯一的问题是名称strcmp并不表示差异;如果有的话,它暗示了相似性。 所以除非你注意,否则很容易误读

if(!strcmp(string1, string2))

就像说,"如果字符串不一样,就做某事",而实际上,它真正说的是"如果两个字符串相同,就做点什么"。

如果strcmp's名字改strdiff,情况可能会更好。 然后你可以写

if(!strdiff(string1, string2))

而且读起来会很好。 (然而,还有其他问题:一些程序员可能会写if(strdiff(string1, string2) == TRUE),并想知道为什么它不起作用。

我们在这里面对的是编程风格的一个点:线

if(!strcmp(string1, string2))

可能工作正常,但阅读起来令人困惑,当有人粗心维护程序时,可能会导致以后的错误。

当您看到该行时

if(!strcmp(string1, string2))

帮助理解它的一种方法是在心理上将名称strcmp翻译成strdiffstrings_are_different,然后您对if陈述进行正确的解释。

我,在一个有很多字符串要比较的程序中,我写

#define Streq(s1, s2) (strcmp(s1, s2) == 0)

之后我可以写

if(Streq(string1, string2))

通过这种方式,我得到了既能正常工作能读起来的东西。

为什么使用 !strcmp 而不是 strcmp?

这是因为代码的作者不是很准确:)

常用的成语是

if( strcmp(p[t], name) == 0 ){

虽然这些记录

if( strcmp(p[t], name) == 0 ){

if(!strcmp(p[t], name)){

是等价的,但第一个更清楚,

如果两个字符串相同,该函数strcmp返回 0。

来自 C 标准(7.23.4 比较函数)

1 比较函数返回的非零值的符号 MEMCMP、strcmp 和 strncmp 由 第一对字符的值之间的差异(两者 解释为无符号字符),其对象不同 比较

和(7.23.4.2 strcmp 函数)

3 strcmp 函数返回一个大于、等于或的整数 小于零,因此 S1 指向的字符串更大 大于、等于或小于 S2 指向的字符串。

至于你的代码,那么它有一个错误。

对于初学者来说,将数组names声明为全局是没有意义的。它应该在主要像

const char * names[] = {"Sushant", "Jhon", "Robin", "Mark", NULL};

由于函数search不会更改传递的字符串,因此应该像

int search( const char *p[], const char *name );

应删除函数搜索中的else语句,并删除返回语句

return -1;

必须放在 for 循环之后。例如

int search( const char *p[], const char *name )
{
register int t;
for(t = 0; p[t]; t++){
if( strcmp( p[t], name ) == 0 ){
return t;
}
}
return -1;
}

我将按以下方式定义函数,如下面的演示程序所示

#include <stdio.h>
#include <string.h>
size_t search( const char *p[], const char *name )
{
size_t i = 0;

while ( p[i] && strcmp( p[i], name ) != 0 ) ++i;

return p[i] ? i : -1;
}
int main(void) 
{
const char * names[] = {"Sushant", "Jhon", "Robin", "Mark", NULL};
size_t i = search(names, "Sushant");

if ( i != -1 ) puts( names[i] );

return 0;
}

根据man strcmp,如果字符串相同,strcmp 返回 0。由于 0 在布尔上下文中表示 false,因此我们需要用!strcmp进行否定来检查两个字符串是否相等。

>返回值
strcmp() 和 strncmp() 函数返回一个大于、等于或小于 0 的整数,因为字符串 s1 大于、等于或小于字符串 s2。

其他人已经给出了很好的答案,所以我不会详细介绍。为了完整起见,我会提到这是因为它可以返回三个不同的值,因为如果字符串不相等,那么它会告诉您哪个字符串"更大",并带有返回值的符号。

在相等时返回 1 是没有意义的,因为您需要两个不同的"假"值。

所有C问题的一般答案是:C是一种非常古老的语言,比今天的大多数最佳实践早了几十年。这是从1971年开始的。许多最佳实践尚未被发现,并且该语言是为计算机设计的,其功能不如大多数人今天想象的那么强大。就像PDP-7(按照今天的货币价值,将花费67万美元)只有9.2kB内存。它甚至没有显示器。它有一台打印机。在C早期,角落几乎到处都被削减。该语言的目标是使编写可以在这些系统上运行的非常小的编译器变得容易。一个优先事项也是尽量减少编写代码所需的字符量。既是因为内存,也是因为打印机和早期显示器的最大线宽。

不要使用!,因为这表明它只返回 true 或 false。相反,请正确比较,例如strcmp(a,b) == 0strcmp(a,b) != 0。如果需要,请使用返回值的符号,如果要编写用于排序的比较函数,则可以使用返回值的符号。

如果它困扰你,写这个包装器:

bool strEqual(const char *a, const char *b) {
return strcmp(a,b) == 0 ? true : false;
}

但我建议不要这样做。有人可能会争辩说它更干净,但它是非标准的。如果你想学习C,那么学习其他代码C。我不会在代码审查中接受该函数。

最新更新