2009-02-27 29 views
11

cuando hago una llamada a la cadena C comparar función como esta:¿Por qué strcmp() devuelve 0 cuando sus entradas son iguales?

strcmp("time","time")

Devuelve 0, lo que implica que las cadenas no son iguales.

¿Alguien puede decirme por qué las implementaciones de C parecen hacer esto? Yo pensaría que devolvería un valor distinto de cero si es igual. Tengo curiosidad por las razones por las que veo este comportamiento.

+0

Time! = Dinero directamente - primero debe emplear una conversión de unidades. –

+4

felicidades a quien haya reelaborado esta pregunta sobre correo no deseado en algo potencialmente útil para los novatos. Sin embargo, todavía no estoy dispuesto a votar, por miedo a que el OP publique nuevamente tales tripas. – rmeador

+3

@remeador: Gracias, pero no insultes al OP. – GEOCHET

Respuesta

22

strcmp devuelve una diferencia léxica (¿o debería llamarlo "comparador de bytes serie de cortocircuito"? :-)) de las dos cadenas que ha dado como parámetros. 0 significa que ambas cadenas son iguales

Un valor positivo significa que s1 estaría después de s2 en un diccionario.

Un valor negativo significa que s1 estaría antes de s2 en un diccionario.

De ahí su valor distinto de cero al comparar "tiempo" y "dinero" que obviamente son diferentes, ¡aunque uno diría que el tiempo es dinero! :-)

+2

strcmp() no hace una comparación léxica, simplemente compara el valor de cada carácter hasta que hay una diferencia o ambas cadenas terminan. – Ferruccio

+0

Podría jurar que he leído documentos que dicen que strcmp() hace una comparación léxica, pero algunos rápidos de Google sugieren que Ferruccio es correcto ...podría haber cambiado en algún momento? – rmeador

+0

No. Siempre de esa manera :-) – Ferruccio

3

parece que quieres strcmp para trabajar como una (hipotética)

int isEqual(const char *, const char *) 

para estar seguro de que sería fiel a la interpretación de "cero es falso" de los resultados enteros, pero complicaría la lógica de clasificación porque, habiendo establecido que las dos cadenas no eran las mismas, aún tendrías que aprender cuál vino "antes".

Por otra parte, sospecho que una implementación común parece

int strcmp(const char *s1, const char *s2){ 
    const unsigned char *q1=s1, *q2=s2; 
    while ((*q1 == *q2) && *q1){ 
     ++q1; ++q2; 
    }; 
    return (*q1 - *q2); 
} 

que es [edición: un poco] elegante en un K & R tipo de camino. El punto importante aquí (que es cada vez más oscurecida por la adquisición del código derecha (evidentemente, debería haber dejado las cosas como estaban)) es la forma en que la instrucción de retorno:

return (*q1 - *q2); 

que da los resultados de la comparación de forma natural en términos de los valores del personaje.

+0

¿No saldría esa "implementación común" del búfer (más allá de la terminación nula?) No veo cómo volvería alguna vez 0 ... –

+0

Creo que tienes que terminar el ciclo si vienes a \ 0 :) u también tiene que ver sobre underflows en * s1 - * s2 para s1 = -127, s2 = 2 => oops :) –

+0

@Daniel: Uh. Sí. Momento mientras soluciono esto ... – dmckee

5

Es común que las funciones devuelvan cero para el caso común o único y casos distintos de cero para casos especiales. Tome la función principal, que convencionalmente devuelve cero en caso de éxito y algún valor distinto de cero en caso de falla. El valor preciso distinto de cero indica qué salió mal. Por ejemplo: falta de memoria, sin derechos de acceso u otra cosa.

En su caso, si la cadena es igual, entonces no hay razón por qué es igual a que las cadenas contienen los mismos caracteres. Pero si no son iguales, entonces el primero puede ser más pequeño o el segundo puede ser más pequeño. Tener que devolver 1 para igual, 0 para más pequeño y 2 para mayor sería de alguna manera extraño, creo.

También puede pensar en ello en términos de la resta:

return = s1 - s2 

Si s1 es "lexicográfico" menos, a continuación, se le dará es un valor negativo.

+0

Estoy bastante seguro de que necesitas desreferenciar tus 's' ... – dmckee

+0

Quise decir que simbólico era un pseudo código. –

+0

Ah. Retiro la sugerencia. – dmckee

0

Supongo que es simplemente por simetría: -1 si es menor, 0 si es igual, 1 si es más.

10

Lo bueno de una implementación de este tipo es que se puede decir

if(strcmp(<stringA>, <stringB>) > 0) // Implies stringA > stringB 
if(strcmp(<stringA>, <stringB>) == 0) // Implies stringA == stringB 
if(strcmp(<stringA>, <stringB>) < 0) // Implies stringA < stringB 
if(strcmp(<stringA>, <stringB>) >= 0) // Implies stringA >= stringB 
if(strcmp(<stringA>, <stringB>) <= 0) // Implies stringA <= stringB 
if(strcmp(<stringA>, <stringB>) != 0) // Implies stringA != stringB 

Nota cómo la comparación con 0 coincide exactamente con la comparación de la implicación.

+1

Hay una macro maravillosa/horrible de las preguntas frecuentes comp.lang.c que implementa casi exactamente este comportamiento de cadena. '#define StrTest (str1, op, str2) (strcmp (str1, str2) op 0)' Con ella, escribirías 'if (StrTest (stringA, ==, stringB))' y tus amigos. Estoy en la duda de si es una idea horrible o una idea maravillosa. –

2

Hay tres posibles resultados: la cadena 1 viene antes de la cadena 2, la cadena 1 viene después de la cadena 2, la cadena 1 es igual que la cadena 2. Es importante mantener estos tres resultados separados; un uso de strcmp() es ordenar cadenas. La pregunta es cómo desea asignar valores a estos tres resultados, y cómo mantener las cosas más o menos consistentes. También puede ver los parámetros para qsort() y bsearch(), que requieren funciones de comparación muy similares a strcmp().

Si desea una función de igualdad de cadenas, devolverá distinto de cero para cadenas iguales y cero para cadenas no iguales, para ir junto con las reglas de C en verdadero y falso. Esto significa que no habría forma de distinguir si la cadena 1 vino antes o después de la cadena 2. Hay múltiples valores verdaderos para una int, o cualquier otro tipo de datos C que quiera nombrar, pero solo uno falso.

Por lo tanto, tener un strcmp útil() que devuelva verdadero para igualdad de cadenas requeriría muchos cambios en el resto del lenguaje, lo que simplemente no sucederá.

4

Otra razón strcmp() devuelve los códigos que hace es para que pueda ser utilizado directamente en la función de la biblioteca estándar qsort(), que le permite ordenar una matriz de cadenas:

#include <string.h> // for strcmp() 
#include <stdlib.h> // for qsort() 
#include <stdio.h> 

int sort_func(const void *a, const void *b) 
{ 
    const char **s1 = (const char **)a; 
    const char **s2 = (const char **)b; 
    return strcmp(*s1, *s2); 
} 

int main(int argc, char **argv) 
{ 
    int i; 
    printf("Pre-sort:\n"); 
    for(i = 1; i < argc; i++) 
     printf("Argument %i is %s\n", i, argv[i]); 
    qsort((void *)(argv + 1), argc - 1, sizeof(char *), sort_func); 
    printf("Post-sort:\n"); 
    for(i = 1; i < argc; i++) 
     printf("Argument %i is %s\n", i, argv[i]); 
    return 0; 
} 

Este pequeño programa de ejemplo ordena sus argumentos ASCIIbéticamente (lo que algunos llamarían léxicamente). Lookie:

$ gcc -o sort sort.c 
$ ./sort hi there little fella 
Pre-sort: 
Argument 1 is hi 
Argument 2 is there 
Argument 3 is little 
Argument 4 is fella 
Post-sort: 
Argument 1 is fella 
Argument 2 is hi 
Argument 3 is little 
Argument 4 is there 

Si strcmp() regresaron 1 (true) por la igualdad de cuerdas y 0 (falso) para los inequal, sería imposible su uso para obtener el grado o dirección de la desigualdad (es decir, cómo diferente, y cuál es más grande) entre las dos cadenas, por lo que es imposible usarlo como una función de clasificación.

No sé qué tan familiarizado estás con C. El código anterior usa algunos de los conceptos más confusos de C: aritmética de punteros, refinanciación de punteros y punteros a funciones, así que si no entiendes algo de ese código, no uses No te preocupes, llegarás a tiempo. Hasta entonces, tendrás muchas preguntas divertidas para hacer en StackOverflow. ;)

Cuestiones relacionadas