如何在 C 中正确比较字符串?

How do I properly compare strings in C?

提问人:nmagerko 提问时间:11/4/2011 最后编辑:chqrlienmagerko 更新时间:8/11/2023 访问量:641032

问:

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

#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);   /* obsolete function: do not use!! */
    printf("I will now repeat this until you type it back to me.\n");

    while (check != input)
    {
        printf("%s\n", input);
        gets(check);   /* obsolete function: do not use!! */
    }

    printf("Good bye!");
    
    return 0;
}

问题是,即使用户()的输入与原始()匹配,我也会不断打印输入字符串。我是否错误地比较了两者?checkinput

c 字符串 strcmp

评论

17赞 lost_in_the_source 1/29/2015
gets( )已从标准中删除。请改用。fgets( )
1赞 Jonathan Leffler 11/23/2016
请注意,为什么 strcmp() 在其输入相等时返回零答案解释了如何比较字符串的相等性、不等式、小于、大于、小于或等于以及大于或等于。并非所有字符串比较都是为了相等。区分大小写的比较又不同了;其他特殊比较(例如字典顺序)需要更专业的比较器,并且还有用于更复杂比较的正则表达式。
0赞 Jonathan Leffler 2/10/2017
还要注意的是,有一个基本上重复的问题:如何检查值是否与几年前询问的字符串匹配。
0赞 Andreas 1/16/2020
这回答了你的问题吗?如何检查值是否与字符串匹配
3赞 RobertS supports Monica Cellio 5/30/2020
这个问题很好,但使用是不行的。自 C11 -> 以来,它也已从标准中删除 请阅读 为什么 gets 函数如此危险,以至于不应该使用它?gets()

答:

368赞 Mysticial 11/4/2011 #1

你不能(有用地)使用 或 比较字符串,你需要使用:!===strcmp

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

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

评论

12赞 Telerik 9/7/2014
在 java 中也是如此,这可能只是与地址进行比较。
43赞 Shravan 6/28/2015
写作就足够了,被认为是好习惯。while (strcmp(check, input))
10赞 Floam 11/11/2017
使用 strncmp 更安全!不希望缓冲区溢出!
1赞 Deduplicator 2/2/2019
@Floam 如果你实际上没有字符串,而是已知长度的非零字符的零填充序列,当然,这将是正确的咒语。但那是完全不同的东西!
1赞 Andrew Henle 3/16/2023
@ADBeveridge并不总是有效,而且实际上是危险的。 并不总是返回以换行符结尾的字符串,因此您的代码可以删除有效数据;实际上可以返回一个长度为零的字符串,这意味着将在数组的边界之外写入并调用未定义的行为。请参阅从 fgets() 输入中删除尾随换行符buffer[strlen(buffer) - 1] = '\0';fgets()fgets()buffer[strlen(buffer) - 1] = '\0';
45赞 AusCBloke 11/4/2011 #2

好的几件事:gets是不安全的,应该被替换,这样你就不会得到缓冲区溢出。fgets(input, sizeof(input), stdin)

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

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

评论

0赞 incompetent 7/18/2019
您能否澄清“\n”和字符串字面量的关系/问题?在将文件的字符串(行)与其他整个文件的字符串(行)进行比较时,我得到的结果不相等。
1赞 Jonathan Leffler 1/16/2020
@incompetent — 如果您从带有 的文件中读取一行,则字符串可能是因为保留了换行符。如果将其与 进行比较,则将得到“不相等”,因为读取数据中的空字节终止符和换行符之间存在差异。所以,你必须删除换行符。可靠的单行方法是,无论缓冲区中是否有任何数据,或者该数据是否以换行符结尾,它都具有正常工作的优点。其他删除换行符的方法很容易崩溃。fgets()"abc\n"fgets()"abc""abc"buffer[strcspn(buffer, "\n")] = '\0';
0赞 RobertS supports Monica Cellio 5/30/2020
这个答案准确地解决了代码的问题,而被点赞和接受最多的答案只涵盖了回答问题的标题。特别是提到最后一段是超级棒的。+1
12赞 mugetsu 4/6/2015 #3

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

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 4/6/2015
您能否添加有关您的解决方案的更多详细信息?
0赞 mugetsu 4/6/2015
是的,这是 strcmp 函数和 solition 的替代品,而不使用 string.h 标头@Jongware
3赞 lukasrozs 10/6/2017
这是行不通的。当在其中一个字符串中找到时,它不会检查另一个字符串。该函数返回 (“equal”),即使一个字符串只是另一个字符串的前缀(例如,和 )。checker'\0''\0'1"foo""foobar"
2赞 lukasrozs 10/6/2017
我会用 .||&&
19赞 Box Box Box Box 2/13/2016 #4

使用 strcmp

这在图书馆里,非常受欢迎。 如果字符串相等,则返回 0。有关返回内容的更好解释,请参阅此内容string.hstrcmpstrcmp

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

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

while (!strcmp(check,input))

while (strcmp(check,input))

您可以查看教程。strcmp

6赞 Vishwanath Tallalli 3/4/2016 #5

每当您尝试比较字符串时,请将它们与每个字符进行比较。为此,您可以使用名为 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");  
} 
-2赞 Rupani T D 3/23/2018 #6
    #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;
    }

这是一个非常简单的解决方案,您可以在其中获得所需的输出。

评论

3赞 chux - Reinstate Monica 1/10/2019
gets();自 C11 以来,它不是标准 C 的一部分。
3赞 chux - Reinstate Monica 1/10/2019
strcmp(s1,s2)是 UB,因为一开始没有指定内容。s2
0赞 not2qubit 7/10/2019
如果您也可以以某种形式提供此代码片段的输出,那就太好了。
3赞 chux - Reinstate Monica 1/11/2019 #7

如何正确比较字符串?

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 != 输入不够

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

字符串是以第一个 null 字符结尾并包含第一个 null 字符的连续字符序列。
C11 §7.1.1 1

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

的内容可以变成字符串input

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

下面的 和 转换为第一个元素的各自地址,然后比较这些地址。checkinput

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

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

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

该函数将 所指向的字符串与 所指向的字符串进行比较。strcmps1s2

该函数返回一个大于、等于或小于零的整数, 因此,由于 所指向的字符串大于、等于或小于 所指向的字符串。strcmps1s2

代码不仅可以发现字符串是否具有相同的数据,还可以发现当它们不同时哪个更大/更小。

当字符串不同时,以下情况为 true。

strcmp(check, input) != 0

有关见解,请参阅创建我自己的 strcmp() 函数

10赞 thb 2/2/2019 #8

欢迎来到指针的概念。一代又一代的初级程序员发现这个概念难以捉摸,但如果你想成长为一个称职的程序员,你必须最终掌握这个概念——而且,你已经问了正确的问题。很好。

你清楚地址是什么吗?请看下图:

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

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

图中的两个框表示两个不同的内存位置。你可以把它们想象成房子。整数 1 位于地址 0x4000 的内存位置(例如“4000 Elm St.”)。整数 7 位于地址 0x4004 的内存位置(例如“4004 Elm St.”)。

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

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

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

3赞 mustafa candan 4/6/2021 #9

你需要使用,你需要strcmp()#include <string.h>

and 运算符仅比较这些字符串的基址。不是字符串的内容!===

while (strcmp(check, input))

示例代码:

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

int main()
{
    char input[40];
    char check[40] = "end\n"; //dont forget to check for \n

    while ( strcmp(check, input) ) //strcmp returns 0 if equal
    {
        printf("Please enter a name: \n");
        fgets(input, sizeof(input), stdin);
        printf("My name is: %s\n", input);
    }

    printf("Good bye!");
    return 0;
}

注1:不安全。请改用gets()fgets()

注意2:使用时也需要检查换行符fgets()'\n'

4赞 Anic17 7/19/2021 #10

您可以:

使用 from ,这是更简单的版本strcmp()string.h

或者,如果你想自己滚动,你可以使用这样的东西:

int strcmp(const char *s1, const char *s2)
{
    for (i = 0; s1[i] != '\0' || s2[i] != '\0'; i++)
    {
        if (s1[i] != s2[i])
        {
            return (unsigned char)s1[i] < (unsigned char)s2[i] ? -1 : 1;
        }
    }
    return 0;
}

我会以这样的方式使用:strcmp()

while (strcmp(check, input))
{
    // code here
}

评论

0赞 Harrison 7/20/2021
您可能想在 strcmp 函数的末尾放置一个return 0;
0赞 Anic17 7/20/2021
这不是必需的,但是的,这是一个很好的做法
0赞 chqrlie 8/11/2023
我冒昧地修复了您的函数的原型和实现。它必须根据不同字符串参数的字典顺序返回负值或正值,并且您忘记初始化为: 循环比循环更不容易出错。此外,如果其中一个字符串是另一个字符串的前缀,则代码返回 0。最后一个是必需的,否则该函数将对相同的字符串具有未定义的行为。strcmpi0forwhilereturn
-2赞 Bele 8/10/2023 #11

我刚刚开始编码并开始在 YouTube 上观看 CS50 视频。在那里我遇到了一个问题,您不能使用“==”比较两个字符串。所以我试了一下:

#include <iostream>

using namespace std;

int main()
{

   string str[] = {"tom", "chris"};

   if (str[0] == "tom")
   {
       return 0;
   }

return 1;
}

由于某种原因,程序工作并返回 0。这里的视频和帖子另有说明。

评论

4赞 chqrlie 8/10/2023
该程序之所以有效,是因为数组的第一个元素和比较中的字符串文字恰好是相同的全局以 null 结尾的数组。这很常见,但 C 标准并不能保证。此外,这种比较不适用于任何其他字符串。不要依赖这种巧合和使用。"tom"charstrcmp()