Como comparo corretamente as strings?


182

Estou tentando obter um programa para permitir que um usuário insira uma palavra ou caractere, armazene-o e imprima-o até que o usuário digite novamente, saindo do programa. Meu código fica assim:

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

O problema é que eu continuo recebendo a impressão da sequência de entrada, mesmo quando a entrada do usuário (cheque) corresponde ao original (entrada). Estou comparando os dois incorretamente?


13
gets( )foi removido do padrão. Use em fgets( )vez disso.
Edward Karak

1
Observe que esta resposta para Por que strcmp()retornar zero quando suas entradas são iguais explica como comparar seqüências de caracteres para igualdade, desigualdade, menor que, maior que, menor que ou igual e maior que ou igual. Nem todas as comparações de strings são para igualdade. As comparações sensíveis a maiúsculas e minúsculas são diferentes novamente; outras comparações especiais (ordem do dicionário, por exemplo) requerem comparadores mais especializados e existem expressões regulares para comparações ainda mais complexas.
Jonathan Leffler

Observe também que há uma pergunta essencialmente duplicada. Como verifico se um valor corresponde a uma sequência que foi solicitada anos antes disso.
9788 Jonathan-Leffler-


Esta pergunta é boa, mas o uso de gets()é um não-go. Também foi removida do padrão desde C11 -> Por favor, leia Por que a função gets é tão perigosa que não deve ser usada?
RobertS apoia Monica Cellio

Respostas:


276

Você não pode (utilmente) comparar seqüências de caracteres usando !=ou ==, você precisa usar strcmp:

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

A razão para isso é porque !=e ==comparará apenas os endereços base dessas strings. Não é o conteúdo das próprias strings.


10
o mesmo em java, que pode ser comparado apenas com o endereço.
Telerik

29
Escrever while (strcmp(check, input))é suficiente e é considerado uma boa prática.
Shiva


7
É mais seguro usar o strncmp! Não quero um estouro de buffer!
Floam

@ Flloam Se você realmente não tem strings, mas seqüências preenchidas com zero de caracteres diferentes de zero e com comprimento conhecido, com certeza, esse seria o encantamento certo. Mas isso é algo completamente diferente!
Deduplicator

33

Ok, algumas coisas: getsé inseguro e deve ser substituído por, fgets(input, sizeof(input), stdin)para que você não obtenha um estouro de buffer.

Em seguida, para comparar cadeias, você deve usar strcmp, onde um valor de retorno 0 indica que as duas cadeias correspondem. O uso dos operadores de igualdade (ie. !=) Compara o endereço das duas cadeias, em oposição aos indivíduos chardentro delas.

E observe também que, embora neste exemplo não cause problemas, fgetsarmazena o caractere de nova linha, '\n'nos buffers também; gets()não. Se você comparasse a entrada do usuário de fgets()uma string literal como "abc"nunca corresponderia (a menos que o buffer fosse muito pequeno para que '\n'ele não caísse nele).


Você pode esclarecer a relação / problema de "\ n" e literal de string? Não estou obtendo resultado igual na comparação de strings (linha) de um arquivo com outro arquivo inteiro.
incompetente

@competent - se você ler uma linha de um arquivo fgets(), a string pode ser "abc\n"porque fgets()mantém a nova linha. Se você comparar isso com "abc", você obterá 'not equal' devido à diferença entre um byte nulo que termina "abc"e a nova linha nos dados lidos. Então, você precisa zapear a nova linha. A maneira confiável de uma linha de fazer isso é o buffer[strcspn(buffer, "\n")] = '\0';que tem o mérito de funcionar corretamente, independentemente de haver algum dado no buffer ou se esse dado termina com uma nova linha ou não. Outras formas de zapear a nova linha são facilmente travadas.
Jonathan Leffler

Esta resposta aborda os problemas do código com precisão, enquanto a resposta mais votada e aceita cobre apenas para responder ao título da pergunta. Especialmente para mencionar o último parágrafo é super. +1
RobertS apoia Monica Cellio

11

Use strcmp.

Isso está na string.hbiblioteca e é muito popular. strcmpretorne 0 se as seqüências de caracteres forem iguais. Veja isso para uma melhor explicação do que strcmpretorna.

Basicamente, você tem que fazer:

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

ou

while (!strcmp(check,input))

ou

while (strcmp(check,input))

Você pode verificar isso , um tutorial sobre strcmp.


7

Você não pode comparar matrizes diretamente assim

array1==array2

Você deve compará-los char a char; para isso, você pode usar uma função e retornar um valor booleano (True: 1, False: 0). Em seguida, você pode usá-lo na condição de teste do loop while.

Tente o seguinte:

#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
Você poderia adicionar mais detalhes sobre sua solução?
Abarisone

sim este é substituto para a função strcmp e solition sem usar string.h cabeçalho @Jongware
Mugetsu

2
Isso não funciona. Quando checkerencontra '\0'em uma das cadeias, não verifica a outra cadeia '\0'. A função retorna 1("igual") mesmo que uma sequência seja apenas o prefixo da outra (por exemplo, "foo"e "foobar").
Lukasrozs

1
Eu usaria em ||vez de &&.
Lukasrozs # 6/17

3

Bem-vindo ao conceito do ponteiro. Gerações de programadores iniciantes acharam o conceito ilusório, mas se você deseja se tornar um programador competente, deve dominar esse conceito - além disso, você já está fazendo a pergunta certa. Isso é bom.

Está claro para você o que é um endereço? Veja este diagrama:

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

No diagrama, o número inteiro 1 é armazenado na memória no endereço 0x4000. Por que em um endereço? Como a memória é grande e pode armazenar muitos números inteiros, assim como uma cidade é grande e pode abrigar muitas famílias. Cada número inteiro é armazenado em um local de memória, pois cada família reside em uma casa. Cada local de memória é identificado por um endereço , assim como cada casa é identificada por um endereço.

As duas caixas no diagrama representam dois locais distintos de memória. Você pode pensar neles como se fossem casas. O número inteiro 1 reside na localização da memória no endereço 0x4000 (pense em "4000 Elm St."). O número inteiro 7 reside no local da memória no endereço 0x4004 (pense em "4004 Elm St.").

Você pensou que seu programa estava comparando o 1 ao 7, mas não estava. Ele estava comparando o 0x4000 ao 0x4004. Então, o que acontece quando você tem essa situação?

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

Os dois números inteiros são iguais, mas os endereços diferem. Seu programa compara os endereços.


2

Sempre que você estiver tentando comparar as strings, compare-as com relação a cada caractere. Para isso, você pode usar a função de string incorporada chamada strcmp (input1, input2); e você deve usar o arquivo de cabeçalho chamado#include<string.h>

Tente este código:

#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

Como comparo corretamente as strings?

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

Vamos nos aprofundar para ver por que check != inputnão é suficiente .

Em C, string é uma especificação de biblioteca padrão.

Uma sequência é uma sequência contígua de caracteres terminados por e incluindo o primeiro caractere nulo.
C11 §7.1.1 1

inputacima não é uma string . inputé matriz 40 de caracteres .

O conteúdo de inputpode se tornar uma string .

Na maioria dos casos, quando uma matriz é usada em uma expressão, ela é convertida no endereço do seu primeiro elemento.

O abaixo converte checke inputpara seus respectivos endereços do primeiro elemento, então esses endereços são comparados.

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

Para comparar strings , precisamos usar esses endereços e, em seguida, examinar os dados para os quais eles apontam.
strcmp()faz o trabalho . §7.23.4.2

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

A strcmpfunção compara a sequência apontada por s1com a sequência apontada por s2.

A strcmpfunção retorna um número inteiro maior que, igual a ou menor que zero, conforme a string apontada por s1é maior que, igual a ou menor que a string apontada por s2.

O código não apenas pode descobrir se as seqüências de caracteres têm os mesmos dados, mas qual é maior / menor quando elas diferem.

O abaixo é verdadeiro quando a string é diferente.

strcmp(check, input) != 0

Para obter informações, consulte Criando minha própria strcmp()função


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

Esta é uma solução muito simples na qual você obterá sua saída conforme desejar.


2
gets();não faz parte do padrão C desde C11.
chux - Reinstala Monica

2
strcmp(s1,s2)é UB, pois o s2conteúdo não é especificado primeiro.
chux - Reinstala Monica

Seria ótimo se você também pudesse fornecer a saída desse snippet, de uma forma ou de outra.
Not2qubit
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.