如何正确比较字符串?


182

我试图获得一个程序,让用户输入单词或字符,存储它,然后打印它,直到用户再次键入它,退出程序。我的代码如下所示:

#include <stdio.h>

int main()
{
    char input[40];
    char check[40];
    int i=0;
    printf("Hello!\nPlease enter a word or character:\n");
    gets(input);
    printf("I will now repeat this until you type it back to me.\n");

    while (check != input)
    {
        printf("%s\n", input);
        gets(check); 
    }

    printf("Good bye!");


    return 0;
}

问题是,即使用户输入(检查)与原始输入(输入)匹配,我仍会继续打印输入字符串。我是否错误地比较了两者?


13
gets( )已从标准中删除。使用fgets( )代替。
爱德华·卡拉克

1
请注意,当输入相等时为什么会返回零的答案解释了如何比较字符串是否相等,不相等,小于,大于,小于或等于以及大于或等于。并非所有的字符串比较都是为了相等。区分大小写的比较再次有所不同。其他特殊比较(例如,字典顺序)需要更专门的比较器,并且存在用于更复杂比较的正则表达式。strcmp()
乔纳森·勒夫勒

还要注意,实际上存在一个重复的问题,即如何检查值是否与之前几年问过的字符串匹配
乔纳森·勒夫勒

这回答了你的问题了吗?如何检查值是否与字符串匹配
Andreas

这个问题很好,但不能使用gets()。自C11以来,它也已从标准中删除->请阅读为什么gets功能如此危险以至于不应使用?
RobertS

Answers:


274

您不能使用!=或比较有用的字符串==,而需要使用strcmp

while (strcmp(check,input) != 0)

这样做的原因是因为!=并且==只会比较那些字符串的基地址。不是字符串本身的内容。


10
在Java中相同,可能只是与地址进行比较。
Telerik 2014年

29
写作while (strcmp(check, input))就足够了,被认为是好的做法。
湿婆


7
使用strncmp更安全!不想缓冲区溢出!
Floam

@Floam如果您实际上没有字符串,但是用零填充的已知长度的非零字符序列,那肯定是正确的。但这是完全不同的!
Deduplicator

33

好几件事:gets是不安全的,应该替换为fgets(input, sizeof(input), stdin)不使缓冲区溢出。

接下来,要比较字符串,必须使用strcmp,其中返回值0表示两个字符串匹配。使用相等运算符(即!=)比较两个字符串的地址,而不是两个字符串中的单个chars 的地址。

还要注意,虽然在此示例中不会造成问题,但也将fgets换行符存储'\n'在缓冲区中;gets()才不是。如果将用户输入与fgets()字符串文字之类的字符串文字进行比较,则该字符串"abc"将永远不匹配(除非缓冲区太小,以致'\n'不能容纳其中的文字)。


您能否阐明“ \ n”和字符串文字的关系/问题?在将文件的字符串(行)与其他整个文件进行比较时,我得到的结果不相等。
不称职的

@incompetent —如果您使用读取文件中的一行fgets(),则该字符串可能是"abc\n"因为fgets()保留了换行符。如果将其与进行比较,"abc"则由于空字节终止"abc"与读取数据中的换行符之间的差异,将得到“不相等” 。因此,您必须换行。一种可靠的单行方法是buffer[strcspn(buffer, "\n")] = '\0';具有正确工作的优点,而不管缓冲区中是否有任何数据,或者该数据是否以换行符结尾。换行的其他方式很容易崩溃。
乔纳森·莱夫勒

这个答案准确地解决了代码的问题,而最受欢迎和接受度最高的答案仅是回答问题的标题。特别要提到的最后一段是超级。+1
RobertS

11

使用strcmp

这是在string.h图书馆,很受欢迎。strcmp如果字符串相等,则返回0。请参阅此内容以更好地解释strcmp返回的结果。

基本上,您必须执行以下操作:

while (strcmp(check,input) != 0)

要么

while (!strcmp(check,input))

要么

while (strcmp(check,input))

您可以在上查看教程strcmp


7

你不能像这样直接比较数组

array1==array2

您应该逐个字符地进行比较;为此,您可以使用函数并返回布尔值(True:1,False:0)。然后,您可以在while循环的测试条件下使用它。

试试这个:

#include <stdio.h>
int checker(char input[],char check[]);
int main()
{
    char input[40];
    char check[40];
    int i=0;
    printf("Hello!\nPlease enter a word or character:\n");
    scanf("%s",input);
    printf("I will now repeat this until you type it back to me.\n");
    scanf("%s",check);

    while (!checker(input,check))
    {
        printf("%s\n", input);
        scanf("%s",check);
    }

    printf("Good bye!");

    return 0;
}

int checker(char input[],char check[])
{
    int i,result=1;
    for(i=0; input[i]!='\0' || check[i]!='\0'; i++) {
        if(input[i] != check[i]) {
            result=0;
            break;
        }
    }
    return result;
}

1
您能否添加有关您的解决方案的更多详细信息?
abarisone 2015年

是的,这是在不使用string.h头文件@Jongware的情况下替换strcmp函数和隔离的功能
mugetsu 2015年

2
这是行不通的。当checker认定'\0'在字符串中的一个,它不检查的另一个字符串'\0'1即使一个字符串只是另一个字符串的前缀(例如"foo""foobar"),该函数也会返回(“等于” )。
lukasrozs

1
我会用||代替&&
lukasrozs

3

欢迎使用指针的概念几代初学者已经发现这个概念难以捉摸,但是如果您想成长为一个有能力的程序员,则必须最终掌握这个概念,而且,您已经在提出正确的问题了。非常好。

您知道地址是什么吗?看到这个图:

----------     ----------
| 0x4000 |     | 0x4004 |
|    1   |     |    7   |
----------     ----------

在该图中,整数1存储在地址 0x4000的内存中。为什么要在一个地址?因为内存很大并且可以存储许多整数,所以就像一个城市很大并且可以容纳许多家庭一样。每个整数都存储在一个内存位置,因为每个家庭都住在房子里。每个存储位置都由一个地址标识,因为每个房屋都由一个地址标识。

图中的两个方框代表两个不同的内存位置。您可以将它们视为房屋。整数1驻留在地址0x4000的存储位置中(例如,“ 4000 Elm St.”)。整数7驻留在地址0x4004的存储位置中(例如,“ 4004 Elm St.”)。

您以为您的程序正在将1与7进行比较,但事实并非如此。它正在比较0x4000与0x4004。那么当您遇到这种情况时会发生什么呢?

----------     ----------
| 0x4000 |     | 0x4004 |
|    1   |     |    1   |
----------     ----------

这两个整数相同,但地址不同。您的程序将比较地址。


2

每当您尝试比较字符串时,请针对每个字符进行比较。为此,您可以使用内置的字符串函数strcmp(input1,input2); 并且您应该使用名为#include<string.h>

试试这个代码:

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h>  

int main() 
{ 
    char s[]="STACKOVERFLOW";
    char s1[200];
    printf("Enter the string to be checked\n");//enter the input string
    scanf("%s",s1);
    if(strcmp(s,s1)==0)//compare both the strings  
    {
        printf("Both the Strings match\n"); 
    } 
    else
    {
        printf("Entered String does not match\n");  
    } 
    system("pause");  
} 

0

如何正确比较字符串?

char input[40];
char check[40];
strcpy(input, "Hello"); // input assigned somehow
strcpy(check, "Hello"); // check assigned somehow

// insufficient
while (check != input)

// good
while (strcmp(check, input) != 0)
// or 
while (strcmp(check, input))

让我们更深入地了解为什么check != input还不够

在C中,字符串是标准库规范。

是由封端的字符的连续序列,并且包括第一个空字符。
C11§7.1.11

input上面不是字符串inputchar的数组40

的内容input可以成为字符串

在大多数情况下,在表达式中使用数组时,会将其转换为其第一个元素的地址。

下面将check和转换input为它们各自的第一个元素的地址,然后将这些地址进行比较。

check != input   // Compare addresses, not the contents of what addresses reference

为了比较字符串,我们需要使用这些地址,然后查看它们指向的数据。
strcmp()做这份工作。§7.23.4.2

int strcmp(const char *s1, const char *s2);

strcmp函数将所指向的字符串与所s1指向的字符串进行比较s2

strcmp函数返回一个大于,等于或小于零的整数,因此,由s1所指向的字符串大于,等于或小于由所指向的字符串s2

代码不仅可以找到字符串是否具有相同的数据,而且还可以发现字符串不同时哪个更大/更少。

字符串不同时,以下内容成立。

strcmp(check, input) != 0

如需了解,请参阅创建我自己的strcmp()函数


-2
    #include<stdio.h>
    #include<string.h>
    int main()
    {
        char s1[50],s2[50];
        printf("Enter the character of strings: ");
        gets(s1);
        printf("\nEnter different character of string to repeat: \n");
        while(strcmp(s1,s2))
        {
            printf("%s\n",s1);
            gets(s2);
        }
        return 0;
    }

这是一个非常简单的解决方案,您可以根据需要获得输出。


2
gets();自C11以来不属于标准C。
chux-恢复莫妮卡

2
strcmp(s1,s2)是UB,因为s2首先没有指定内容。
chux-恢复莫妮卡

如果您还可以以某种形式或其他形式提供此代码段的输出,那就太好了。
not2qubit
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.