¿Por qué strcmp () devuelve 0 cuando sus entradas son iguales?

Cuando realizo una llamada a la función de comparación de cadenas C de esta manera:

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.

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 serí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! 🙂

Lo bueno de una implementación como esta es que puedes decir

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

Observe cómo la comparación con 0 coincide exactamente con la comparación en la implicación.

Es común que las funciones devuelvan cero para el caso común o uno único y 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 ninguna razón por la cual sea igual a que las cadenas contengan 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 puedes pensarlo en términos de resta:

 return = s1 - s2 

Si s1 es “lexicográficamente” menor, entonces dará un valor negativo.

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

 #include  // for strcmp() #include  // for qsort() #include  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 progtwig de muestra clasifica sus argumentos ASCIIbetically (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() devolviera 1 (verdadero) para cadenas iguales y 0 (falso) para las desiguales, sería imposible usarlo para obtener el grado o la dirección de la desigualdad (es decir, qué tan diferente y cuál es más grande) entre los 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 te preocupes, llegarás a tiempo. Hasta entonces, tendrás muchas preguntas divertidas para hacer en StackOverflow. 😉

Parece que quieres que strcmp funcione como un (hipotético)

 int isEqual(const char *, const char *) 

Para estar seguro de que eso sería cierto para la interpretación “cero es falso” de los resultados enteros, pero complicaría la lógica de clasificación porque, una vez establecido que las dos cadenas no eran las mismas, aún tendría que aprender cuál vino “antes”. “.

Además, sospecho que una implementación común se parece a

 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 [ edit: algo] elegante en una especie de K & R. El punto importante aquí (que está cada vez más oscurecido al obtener el código correcto (evidentemente debería haberlo dejado lo suficientemente bien solo)) es la forma en que la statement de retorno:

  return (*q1 - *q2); 

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

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 quisiera una función de igualdad de cadenas, devolvería un valor 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 la igualdad de cadenas requeriría muchos cambios en el rest del lenguaje, lo que simplemente no sucederá.

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