¿Cómo comparo correctamente las cadenas?


183

Estoy tratando de obtener un programa para permitir que un usuario ingrese una palabra o carácter, lo almacene y luego lo imprima hasta que el usuario lo vuelva a escribir, saliendo del programa. Mi código se ve así:

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

El problema es que sigo obteniendo la impresión de la cadena de entrada, incluso cuando la entrada del usuario (cheque) coincide con el original (entrada). ¿Estoy comparando los dos incorrectamente?


13
gets( )fue eliminado de la norma. Usar en su fgets( )lugar.
Edward Karak el

1
Tenga en cuenta que esta respuesta a Por qué strcmp()devuelve cero cuando sus entradas son iguales explica cómo comparar las cadenas de igualdad, desigualdad, menor que, mayor que, menor que o igual, y mayor que o igual. No todas las comparaciones de cadenas son para la igualdad. Las comparaciones sensibles a mayúsculas y minúsculas son diferentes nuevamente; otras comparaciones especiales (orden de diccionario, por ejemplo) requieren comparadores más especializados, y hay expresiones regulares para comparaciones aún más complejas.
Jonathan Leffler

Tenga en cuenta también que hay una pregunta esencialmente duplicada. ¿ Cómo verifico si un valor coincide con una cadena que se preguntó años antes?
Jonathan Leffler


Esta pregunta es buena, pero no se puede usar gets(). También se ha eliminado del estándar desde C11 -> Lea ¿
RobertS apoya a Monica Cellio

Respuestas:


276

No puede (útilmente) comparar cadenas usando !=o ==, debe usar strcmp:

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

La razón de esto es porque !=, y ==sólo comparar las direcciones base de esas cadenas. No el contenido de las cadenas en sí.


10
Lo mismo en Java, que puede compararse con la dirección.
Telerik

29
Escribir while (strcmp(check, input))es suficiente y se considera una buena práctica.
Shiva


77
¡Es más seguro usar strncmp! ¡No quiero un desbordamiento de búfer!
Floam

@Floam Si en realidad no tiene cadenas, sino secuencias rellenas con cero de caracteres distintos de cero de longitud conocida, seguro, ese sería el encantamiento correcto. ¡Pero eso es algo completamente diferente!
Deduplicador

33

Ok algunas cosas: getsno es seguro y debe reemplazarse confgets(input, sizeof(input), stdin) para que no se desborde el búfer.

Luego, para comparar cadenas, debe usar strcmp, donde un valor de retorno de 0 indica que las dos cadenas coinciden. El uso de los operadores de igualdad (es decir !=) compara la dirección de las dos cadenas, en oposición a las del individuo chardentro de ellas.

Y también tenga en cuenta que, si bien en este ejemplo no causará ningún problema, fgets almacena el carácter de nueva línea, también '\n'en los búferes; gets()no. Si compara la entrada del usuario desde fgets()un literal de cadena como "abc"nunca coincidiría (a menos que el búfer fuera demasiado pequeño para que '\n'no entrara).


¿Puede por favor aclarar la relación / problema de "\ n" y el literal de cadena? No obtengo el mismo resultado al comparar las cadenas (línea) de un archivo con otro archivo completo.
incompetente

@ incompetente: si lee una línea de un archivo con fgets(), entonces la cadena podría ser "abc\n"porque fgets()mantiene la nueva línea. Si compara eso con "abc", obtendrá "no igual" debido a la diferencia entre un byte nulo que termina "abc"y la nueva línea en los datos leídos. Entonces, tienes que eliminar la nueva línea. La forma confiable de hacerlo en una línea es buffer[strcspn(buffer, "\n")] = '\0';tener el mérito de funcionar correctamente, independientemente de si hay datos en el búfer o si esos datos terminan con una nueva línea o no. Otras formas de zapping de la nueva línea se bloquean fácilmente.
Jonathan Leffler

Esta respuesta aborda los problemas del código con precisión, mientras que la respuesta más votada y aceptada cubre solo el título de la pregunta. Especialmente mencionar el último párrafo es super. +1
RobertS apoya a Monica Cellio

11

Uso strcmp.

Esto está en la string.hbiblioteca, y es muy popular. strcmpdevuelve 0 si las cadenas son iguales. Vea esto para una mejor explicación de lo que strcmpregresa.

Básicamente, tienes que hacer:

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

o

while (!strcmp(check,input))

o

while (strcmp(check,input))

Puedes consultar esto , un tutorial sobre strcmp.


7

No puedes comparar matrices directamente como esta

array1==array2

Deberías compararlos char-by-char; para esto puede usar una función y devolver un valor booleano (True: 1, False: 0). Luego puede usarlo en la condición de prueba del ciclo while.

Prueba esto:

#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
¿Podría agregar más detalles sobre su solución?
abarisone

sí, este es el reemplazo de la función strcmp y la solución sin usar el encabezado string.h @Jongware
mugetsu

2
Esto no funciona. Cuando se checkerencuentra '\0'en una de las cadenas, no verifica la otra cadena '\0'. La función devuelve 1("igual") incluso si una cadena es solo el prefijo de la otra (por ejemplo, "foo"y "foobar").
lukasrozs

1
Yo usaría en ||lugar de &&.
lukasrozs

3

Bienvenido al concepto del puntero.Generaciones de programadores principiantes han encontrado el concepto evasivo, pero si desea convertirse en un programador competente, debe dominar este concepto y, además, ya está haciendo la pregunta correcta. Eso es bueno.

¿Está claro qué es una dirección? Ver este diagrama:

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

En el diagrama, el entero 1 se almacena en la memoria en la dirección 0x4000. ¿Por qué en una dirección? Debido a que la memoria es grande y puede almacenar muchos enteros, así como una ciudad es grande y puede albergar a muchas familias. Cada número entero se almacena en una ubicación de memoria, ya que cada familia reside en una casa. Cada ubicación de memoria se identifica por una dirección , ya que cada casa se identifica por una dirección.

Los dos cuadros en el diagrama representan dos ubicaciones de memoria distintas. Puedes pensar en ellos como si fueran casas. El número entero 1 reside en la ubicación de la memoria en la dirección 0x4000 (piense, "4000 Elm St."). El entero 7 reside en la ubicación de la memoria en la dirección 0x4004 (piense, "4004 Elm St.").

Pensaste que tu programa estaba comparando el 1 con el 7, pero no fue así. Estaba comparando el 0x4000 con el 0x4004. Entonces, ¿qué sucede cuando tienes esta situación?

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

Los dos enteros son iguales pero las direcciones difieren. Su programa compara las direcciones.


2

Siempre que intentes comparar las cadenas, compáralas con respecto a cada personaje. Para esto, puede utilizar la función de cadena integrada llamada strcmp (input1, input2); y deberías usar el archivo de encabezado llamado#include<string.h>

Prueba 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

¿Cómo comparo correctamente las cadenas?

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

Profundicemos más para ver por qué check != inputno es suficiente .

En C, la cadena es una especificación de biblioteca estándar.

Una cadena es una secuencia contigua de caracteres terminados por e incluyendo el primer carácter nulo.
C11 §7.1.1 1

inputarriba no es una cadena . inputes la matriz 40 de char .

El contenido de inputpuede convertirse en una cadena .

En la mayoría de los casos, cuando se usa una matriz en una expresión, se convierte a la dirección de su primer elemento.

El siguiente se convierte checky inputa sus respectivas direcciones del primer elemento, luego se comparan esas direcciones.

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

Para comparar cadenas , necesitamos usar esas direcciones y luego mirar los datos que señalan.
strcmp()hace el trabajo . §7.23.4.2

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

La strcmpfunción compara la cadena apuntada por s1con la cadena apuntada por s2.

La strcmpfunción devuelve un número entero mayor que, igual o menor que cero, en consecuencia, ya que la cadena apuntada por s1es mayor que, igual o menor que la cadena apuntada por s2.

El código no solo puede encontrar si las cadenas son de los mismos datos, sino cuál es mayor / menor cuando difieren.

Lo siguiente es cierto cuando la cadena difiere.

strcmp(check, input) != 0

Para obtener información, vea Crear mi propia strcmp()función


-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 es una solución muy simple en la que obtendrá su salida como desee.


2
gets();no forma parte del estándar C desde C11.
chux - Restablecer Monica

2
strcmp(s1,s2)es UB ya que los s2contenidos no se especifican al principio.
chux - Restablece a Monica

Sería genial si también pudiera proporcionar la salida de este fragmento, de una forma u otra.
not2qubit
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.