web-dev-qa-db-ja.com

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は返されません。誰か助けてもらえますか?そして、ポインタなしでください!

9
blackFish

それは解決策を短くするので残念なポインタ算術を避けたがっているようですが、あなたの問題はあなたが文字列の終わりを越えてスキャンすることです。明示的な区切りを追加すると機能します。プログラムが少し変更されました:

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] == '\0')
        {
            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] == '\0')
        {
            return 0;
        }
    }
}
4
Daniel B.

ええと…複雑すぎる。これに行く:

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

期待どおりに<0、0、または> 0を返します

ポインターなしではそれを行うことはできません。 Cでは、ポインタを使用して配列のインデックスisを作成します。

*演算子の使用を避けたいですか? :-)

27

まず、標準C関数strcmpは、文字列の要素をunsigned char型として比較します。

第2に、定数文字列の比較を提供するために、パラメーターは定数文字列へのポインターでなければなりません。

関数は次のように書くことができます

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 );
}
5

これはstrcmpの10オペコード実装です(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

2
Larytet

here から取得。

#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]!='\0') || (src2[i]!='\0'))
    {
        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!='\0') || (*src2!='\0'))
    {
        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 のように機能するようにいくつかの変更を加えました。

0
Ashish Ahuja

私の実装

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

最後のternary操作はoptionalです

関数は、単に*s1 - *s2を返す場合でも、strcmpの規則に従います。

0
Beyondo

問題は、文字列の終わりを検出しないため、違いが検出される前に両方の文字列が終了した場合にゼロを返さないことです。

ループ状態でこれを確認することで、これを簡単に修正できます。

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

両方の文字列がチェックされることに注意してください。最後の文字列が1つだけの場合、文字列は等しくなく、ループ内の比較でそれが検出されるためです。

文字の比較では期待した結果が得られない場合があることに注意してください。 1つには、charが署名されているか、署名されていないかは定義されていないため、比較のためにunsigned charにキャストする必要があります。

おそらく、より明確な解決策は、違いを検出したときにすぐに戻ることです。つまり、flag = -1の代わりに、直接-1を返します。しかし、それは意見の問題です。

0
skyking