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

Posted

技术标签:

【中文标题】如何正确比较 C 中的字符串?【英文标题】:How do I properly compare strings in 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;

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

【问题讨论】:

gets( ) 已从标准中删除。请改用fgets( ) 请注意,answer 到 Why does strcmp() return zero when its inputs are equal 解释了如何比较字符串的相等、不相等、小于、大于、小于或等于以及大于或等于。并非所有字符串比较都是为了相等。区分大小写的比较再次不同;其他特殊比较(例如字典顺序)需要更专业的比较器,并且有用于更复杂比较的正则表达式。 还要注意,有一个基本重复的问题How do I check if a value matches a string 在此之前几年就被问过了。 这能回答你的问题吗? How do I check if a value matches a string 这个问题很好,但是使用gets() 是不行的。自 C11 起,它也已从标准中删除 -> 请阅读Why is the gets function so dangerous that it should not be used? 【参考方案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))

您可以查看this,strcmp上的教程。

【讨论】:

【参考方案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[]="***";
    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 不是字符串input 是 array 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 的输出,那就太好了。

以上是关于如何正确比较 C 中的字符串?的主要内容,如果未能解决你的问题,请参考以下文章

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

如何将字符串与 Bash 中的多个正确值进行比较?

如何在c中使用qsort比较C++字符串?

如何比较 C 条件预处理器指令中的字符串

如何将 uint8_t 数组与 C 中的字符串进行比较?

如何正确编组从Unity到C / C ++的字符串?