【问题标题】:How do I properly compare strings in C?如何正确比较 C 中的字符串?
【发布时间】:2021-09-03 21:56:44
【问题描述】:

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

#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;
}

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

【问题讨论】:

标签: c string strcmp


【解决方案1】:

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

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

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

【讨论】:

  • java中也一样,可能只是和地址比较。
  • while (strcmp(check, input)) 就足够了,被认为是好的做法。
  • 了解更多...codificare.in/codes/c/…
  • 使用strncmp更安全!不希望缓冲区溢出!
  • @craigB 很抱歉打破你的泡沫,但strcmp()"abcde" 大于"abc",不等于它。
【解决方案2】:

好的一些事情:gets is unsafe,应该替换为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
【解决方案3】:

使用strcmp

这是在string.h 库中,非常受欢迎。 strcmp 如果字符串相等则返回 0。请参阅 this 以更好地解释 strcmp 返回的内容。

基本上,你必须这样做:

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

while (!strcmp(check,input))

while (strcmp(check,input))

您可以查看thisstrcmp上的教程。

【讨论】:

    【解决方案4】:

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

    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;
    }
    

    【讨论】:

    • 能否请您添加有关您的解决方案的更多详细信息?
    • 是的,这是 strcmp 函数和 solition 的替代品,不使用 string.h 标头 @Jongware
    • 这不起作用。当checker 在其中一个字符串中找到'\0' 时,它不会检查另一个字符串中的'\0'。即使一个字符串只是另一个字符串的前缀(例如,"foo""foobar"),该函数也会返回 1 ("equal")。
    • 我会使用|| 而不是&amp;&amp;
    【解决方案5】:

    当您尝试比较字符串时,请根据每个字符比较它们。为此,您可以使用名为 strcmp(input1,input2); 的内置字符串函数。你应该使用名为#include&lt;string.h&gt;的头文件

    试试这个代码:

    #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");  
    } 
    

    【讨论】:

      【解决方案6】:

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

      你清楚地址是什么吗?看这张图:

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

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

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

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

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

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

      【讨论】:

        【解决方案7】:

        你需要使用strcmp(),你需要#include &lt;string.h&gt;

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

        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'换行符

        【讨论】:

          【解决方案8】:

          你可以:

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

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

          int strcmp(char *s1, char *s2)
          {
              int i;
              while(s1[i] != '\0' && s2[i] != '\0')
              {
                  if(s1[i] != s2[i])
                  {
                      return 1;
                  }
                  i++;
              }
              return 0;
          }
          

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

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

          【讨论】:

          • 您可能打算在 strcmp 函数的末尾添加一个return 0;
          • 不需要,但是,这是一个很好的做法
          【解决方案9】:

          如何正确比较字符串?

          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 中,string 是标准库规范。

          字符串 是一个连续的字符序列,以第一个空字符终止并包括第一个空字符。
          C11 §7.1.1 1

          上面的

          input 不是字符串inputarray 40 of char

          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);

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

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

          代码不仅可以找出字符串是否属于相同的数据,而且当它们不同时,哪个更大/更少。

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

          strcmp(check, input) != 0
          

          如需深入了解,请参阅Creating my own strcmp() function

          【讨论】:

            【解决方案10】:
                #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;
                }
            

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

            【讨论】:

            • gets(); 自 C11 起不再是标准 C 的一部分。
            • strcmp(s1,s2) 是 UB,因为 s2 最初没有指定内容。
            • 如果你也能以某种形式提供这个 sn-p 的输出,那就太好了。
            猜你喜欢
            相关资源
            最近更新 更多