Реализация strcmp стандарта

Я попытался реализовать strcmp:

int strCmp(char string1[], char string2[] )
{
    int i=0,flag=0;    
    while(flag==0)
    {
        if (string1[i]>string2[i])
        {
            flag=1;
        }
        else if (string1[i]<string2[i])
        {
            flag=-1;
        }
        else
        {
            i++;
        }
    }
    return flag;
}

но я застрял в случае, когда пользователь будет вводить те же строки, потому что функция работает с 1 и -1, но она не возвращает 0. Кто-нибудь может помочь? И пожалуйста, без указателей!

7 ответов


вы, похоже, хотите избежать арифметики указателей, что жаль, так как это делает решение короче, но ваша проблема заключается в том, что вы сканируете за пределами конца строк. Добавление явного перерыва будет работать. Ваша программа слегка изменена:

int strCmp(char string1[], char string2[] )
{
    int i = 0;
    int flag = 0;    
    while (flag == 0)
    {
        if (string1[i] > string2[i])
        {
            flag = 1;
        }
        else if (string1[i] < string2[i])
        {
            flag = -1;
        }

        if (string1[i] == '')
        {
            break;
        }

        i++;
    }
    return flag;
}

краткая версия:

int strCmp(char string1[], char string2[] )
{
    for (int i = 0; ; i++)
    {
        if (string1[i] != string2[i])
        {
            return string1[i] < string2[i] ? -1 : 1;
        }

        if (string1[i] == '')
        {
            return 0;
        }
    }
}

Хм.. слишком сложно. Пойдите для этого:

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

возвращает 0, как и ожидалось

вы не можете сделать это без указателей. В C индексирование массива is С помощью указателей.

возможно, вы хотите избежать использования * оператор? :-)


прежде всего стандартная функция C strcmp сравнивает элементы как строки типа unsigned char.

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

функция может быть записана следующим образом

int strCmp( const char *s1, const char *s2 )
{
    const unsigned char *p1 = ( const unsigned char * )s1;
    const unsigned char *p2 = ( const unsigned char * )s2;

    while ( *p1 && *p1 == *p2 ) ++p1, ++p2;

    return ( *p1 > *p2 ) - ( *p2  > *p1 );
}

это реализация 10 опкодов strcmp (GCC предполагается)

int strcmp_refactored(const char *s1, const char *s2)
{
    while (1)
    {
        int res = ((*s1 == 0) || (*s1 != *s2));
        if  (__builtin_expect((res),0))
        {
            break;
        }
        ++s1;
        ++s2;
    }
    return (*s1 - *s2);
}

вы можете попробовать эту реализацию и сравнить с другими https://godbolt.org/g/ZbMmYM


принято от здесь.

#include<stdio.h>
#include<string.h>

//using arrays , need to move the string using index
int strcmp_arry(char *src1, char *src2)
{
    int i=0;
    while((src1[i]!='') || (src2[i]!=''))
    {
        if(src1[i] > src2[i])
            return 1;
        if(src1[i] < src2[i])
            return 1;
        i++;
    }

    return 0;
}
//using pointers, need to move the position of the pointer
int strcmp_ptr(char *src1, char *src2)
{
    int i=0;
    while((*src1!='') || (*src2!=''))
    {
        if(*src1 > *src2)
            return 1;
        if(*src1 < *src2)
            return 1;
        src1++;
        src2++;
    }
    return 0;
}

int main(void)
{
    char amessage[] = "string";
    char bmessage[] = "string1";
    printf(" value is %d\n",strcmp_arry(amessage,bmessage));
    printf(" value is %d\n",strcmp_ptr(amessage,bmessage));
}

Я сделал несколько изменений, чтобы заставить его работать как strcmp.


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

вы можете просто исправить это, проверив это в условии цикла:

while( flag==0 && (string1[i] != 0 | string2[i] != 0 ) )

обратите внимание, что обе строки проверяются, потому что, если только одна находится в конце, строки не равны, и сравнение внутри цикла должно обнаружить это.

обратите внимание, что сравнение символов может не дать результат, который вы могли бы ожидать. Для одного не определено, является ли char подписано или без знака, поэтому вы, вероятно, должны привести к unsigned char для сравнения.

возможно, более чистым решением было бы немедленно вернуться, когда вы обнаружите разницу, то есть вместо flag = -1 вы возвращаетесь -1 напрямую. Но это скорее вопрос мнения.


Реализация

int strcmp(const char * s1, const char * s2)
{
    while (*s1 == *s2 && *s1++ | *s2++);
    int i = *s1 - *s2;
    return i < 0 ? -1 : i > 0 ? 1 : 0;
}

возвращаемые значения

-1 // <0
1  // >0
0  // ==0

последние троичная операция дополнительно

функция все равно будет в правилах strcmp когда ты вернешься *s1 - *s2.