2010-03-08 23 views
6

Estoy tratando de comparar dos cadenas. Uno almacenado en un archivo, el otro recuperado del usuario (stdin).strcmp en una línea de lectura con fgets

Aquí es un programa de ejemplo:

int main() 
{ 
    char targetName[50]; 
    fgets(targetName,50,stdin); 

    char aName[] = "bob"; 
    printf("%d",strcmp(aName,targetName)); 

    return 0; 
} 

En este programa strcmp, devuelve un valor de -1 cuando la entrada es "bob". ¿Por qué es esto? Pensé que deberían ser iguales. ¿Cómo puedo obtenerlo para que lo sean?

+0

Debe evitar el uso de 'strcmp'. Use 'strncmp' en su lugar, especialmente si está comparando con una cadena de ancho fijo. Usar 'strncmp (aName, targetName, strlen (aName))' debería funcionar para usted aquí. – bta

+0

El comentario de bta es incorrecto: use strncmp si desea compararlo con un prefijo, en lugar de con la cadena completa, de modo que, por ejemplo. "bobcat" también coincidirá. –

+0

Lo dije porque 'strcmp' continuará comparando hasta que se llegue a un terminador NULL o las cuerdas difieran. Si no puede estar seguro de que sus cadenas siempre estarán debidamente terminadas en NULL, 'strcmp' puede introducir desbordamientos de búfer y violaciones de acceso a la memoria. 'strncmp' no es solo para leer prefijos; Establezca el parámetro final en el tamaño de su búfer de longitud fija para asegurarse de que no esté desbordando los límites de su matriz. – bta

Respuesta

8

strcmp es una de las pocas funciones que tiene los resultados inversos de verdadero y falso ... si las cadenas son iguales, el resultado es 0, no 1 como se podría pensar ....

if (strcmp(a, b)) { 
    /* Do something here as the strings are not equal */ 
} else { 
    /* Strings are equal */ 
} 

Hablando de fgets, hay una probabilidad de que hay una nueva línea unida al extremo de la cuerda ... que necesita para deshacerse de él ...

+-+-+-+--+--+ 
|b|o|b|\n|\0| 
+-+-+-+--+--+ 

para deshacerse o Si la nueva línea hace esto. Advertencias: No utilizar "strlen (unNombre) - 1", porque una línea devuelto por fgets puede comenzar con el carácter NUL - por lo tanto el índice en el búfer se convierte en -1:

aName[strcspn(aName, "\n")] = '\0'; 

+-+-+-+--+ 
|b|o|b|\0| 
+-+-+-+--+ 

Ahora, strcmp deberían volver 0 ...

+0

Gracias, otras respuestas fueron buenas, pero la tuya incluía una solución (pensé que el problema podría ser \ n, pero pensé que podría haber sido otra cosa), porque incluyes una solución (y una buena imagen de arreglo jajaja), yo ' he marcado a los tuyos como los mejores. Y sí, ahora strcmp funciona. – Blackbinary

+1

strcmp no revierte los resultados de verdadero y falso. strcmp no devuelve un booleano, devuelve un valor integral en función de cómo las dos cadenas se relacionan entre sí. "if (strcmp (a, b))" funciona, pero oscurece este hecho ya que cuando se trata de valores integrales, la sentencia "if" lo tratará como "if (n! = 0)". Una forma más clara de escribir esto sería "if (strcmp (a, b)! = 0)" que declara explícitamente lo que se está probando. – Torlack

+0

@Torlack: o si (! Strcmp (a, b)) .... independientemente de lo que diga, cualquier cosa que no sea cero es verdadera, y cero es falso, de ahí mi énfasis en ello ... – t0mm13b

1

Porque fgets está incorporando el carácter de nueva línea en la variable targetName. Esto está arrojando fuera de la comparación.

0

fgets anexa la nueva línea a la cadena, por lo que terminará con bob\n\0 que no es lo mismo que bob\0.

0

Principalmente por el final de la línea de caracteres en la entrada "\ n" en unix como sistema.

5

fgets lee hasta que ve una línea nueva y luego regresa, por lo que cuando escribe bob, en la consola, targetName contiene "bob \ n" que no coincide con "bob". Desde el Documenation fgets: (negrita añadida)

lee caracteres de flujo y las almacena como una cadena C en str hasta personajes (num-1) han sido leídos o bien un salto de línea o una al final de vida Se llega al archivo, lo que ocurra primero. Un carácter de nueva línea hace que los fragmentos dejen de leer, pero se considera un carácter válido y, por lo tanto, se incluye en la cadena copiada en str. Un carácter nulo se agrega automáticamente en str después de que los caracteres se leen para señalar el final de la cadena C.

Debe quitar la nueva línea del final de targetName antes de realizar la comparación.

int cch = strlen(targetName); 
if (cch > 1 && targetName[cch-1] == '\n') 
    targetName[cch-1] = '\0'; 

o agregue la nueva línea a su cadena de prueba.

char targetName[50]; 
fgets(targetName,50,stdin); 

char aName[] = "bob\n"; 
printf("%d",strcmp(aName,targetName)); 
+0

Sugiero usar 'sizeof (targetName)', no codificarlo en 'fgets()'. – mctylr

1

El fgets se agrega un \n a la cadena que está tirando del usuario cuando presionen Enter.Puede evitar esto usando strcspn o simplemente agregando \n al final de la cadena que está tratando de comparar.

printf("Please enter put FILE_NAME (foo1, 2, or 3), ls, or exit: \n"); 
fgets(temp, 8, stdin); 
temp[strcspn(temp, "\n")] = '\0'; 
if(strcmp(temp, "ls") == 0 || strcmp(temp, "exit") == 0) 

Esto simplemente se cambia de \n con un \0, pero si quieres ser perezoso que sólo puede hacer esto:

printf("Please enter put FILE_NAME (foo1, 2, or 3), ls, or exit: \n"); 
fgets(temp, 8, stdin); 
if(strcmp(temp, "ls\n") == 0 || strcmp(temp, "exit\n") == 0) 

pero no es tan elegante.

Cuestiones relacionadas