Почему strcmp () возвращает 0, когда его входы равны? - PullRequest
14 голосов
/ 27 февраля 2009

Когда я вызываю функцию сравнения строк C, вот так:

strcmp("time","time")

Возвращает 0, что означает, что строки не равны.

Может кто-нибудь сказать мне, почему реализации C, кажется, делают это? Я думаю, что он будет возвращать ненулевое значение, если равно. Мне любопытно, почему я вижу такое поведение.

Ответы [ 7 ]

25 голосов
/ 27 февраля 2009

strcmp возвращает лексическое различие (или я должен назвать это «последовательный байтовый компаратор короткого замыкания»? :-)) двух строк, которые вы задали в качестве параметров. 0 означает, что обе строки равны

Положительное значение означает, что s1 будет после s2 в словаре.

Отрицательное значение означает, что s1 будет перед s2 в словаре.

Следовательно, ваше ненулевое значение при сравнении «времени» и «денег», которые явно различаются, даже если бы вы сказали, что время - это деньги! : -)

12 голосов
/ 27 февраля 2009

Хорошая вещь о такой реализации, как вы можете сказать

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

Обратите внимание, что сравнение с 0 точно соответствует сравнению в импликации.

6 голосов
/ 27 февраля 2009

Обычно функции возвращают ноль для общего - или единственного в своем роде - случая и ненулевое для особых случаев. Возьмем основную функцию, которая обычно возвращает ноль при успехе и некоторое ненулевое значение при сбое. Точное ненулевое значение указывает на то, что пошло не так. Например: недостаточно памяти, нет прав доступа или что-то еще.

В вашем случае, если строка равна, то нет причины , почему она равна, кроме того, что строки содержат одинаковые символы. Но если они не равны, то либо первое может быть меньше, либо второе может быть меньше. Я думаю, что возвращать 1 для равных, 0 для меньших и 2 для больших было бы странно.

Вы также можете думать об этом с точки зрения вычитания:

return = s1 - s2

Если s1 «лексикографически» меньше, то это даст отрицательное значение.

4 голосов
/ 02 сентября 2009

Еще одна причина, по которой strcmp() возвращает коды, которые он делает, заключается в том, что его можно использовать непосредственно в стандартной библиотечной функции qsort(), позволяющей отсортировать массив строк:

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

Эта небольшая программа-пример сортирует свои аргументы ASCIIbetically (что некоторые называют лексически). 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

Если бы strcmp() вернул 1 (true) для одинаковых строк и 0 (false) для неравных, было бы невозможно использовать его для получения направления Степень или неравенства (т. Е. Насколько оно отличается от того, которое больше) между двумя строками, что делает невозможным его использование в качестве функции сортировки.

Я не знаю, насколько вы знакомы с C. В приведенном выше коде используются некоторые из наиболее запутанных понятий C - арифметика указателей, преобразование указателей и указатели функций - поэтому, если вы не понимаете часть этого кода, не волнуйся, ты доберешься вовремя. А до тех пор у вас будет множество интересных вопросов на StackOverflow. ;)

3 голосов
/ 27 февраля 2009

Вы, кажется, хотите, чтобы strcmp работал как (гипотетически)

int isEqual(const char *, const char *)

Чтобы быть уверенным, что это будет верно для интерпретации целых результатов «ноль - ложь», но это усложнит логику сортировки, потому что, установив, что две строки не совпадают, вам все равно нужно будет узнать, какие пришел "раньше".

Более того, я подозреваю, что общая реализация выглядит как

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

что [ edit: своего рода] элегантно в стиле K & R. Важным моментом здесь (который становится все более и более непонятным из-за правильного кода (очевидно, мне следовало бы оставить его в покое достаточно хорошо)) является способ выражения return:

   return (*q1 - *q2);

, который естественно дает результаты сравнения в терминах значений символов.

2 голосов
/ 27 февраля 2009

Возможны три результата: строка 1 стоит перед строкой 2, строка 1 идет после строки 2, строка 1 совпадает со строкой 2. Важно хранить эти три результата отдельно; Одно из применений strcmp () - сортировка строк. Вопрос в том, как вы хотите присвоить значения этим трем результатам и как сделать вещи более или менее согласованными. Вы также можете взглянуть на параметры для qsort () и bsearch (), которые требуют функции сравнения во многом как strcmp ().

Если бы вы хотели получить функцию равенства строк, она бы возвращала ненулевое значение для одинаковых строк и ноль для неравных строк, чтобы соответствовать правилам Си относительно true и false. Это означает, что не будет никакого способа отличить, была ли строка 1 до или после строки 2. Существует несколько значений true для типа int или любого другого типа данных C, который вы хотите назвать, но только одно значение false.

Следовательно, наличие полезной функции strcmp (), возвращающей true для равенства строк, потребует большого количества изменений в остальной части языка, чего просто не произойдет.

0 голосов
/ 27 февраля 2009

Полагаю, это просто для симметрии: -1, если меньше, 0, если равно, 1, если больше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...