【问题标题】:Implementation of strcmpstrcmp的实现
【发布时间】:2016-04-24 17:09:34
【问题描述】:

我尝试实现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。任何人都可以帮忙吗?请不要指点!

【问题讨论】:

标签: c c-strings strcmp


【解决方案1】:

嗯.. 太复杂了。去这个:

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 中,索引数组使用指针。

也许您想避免使用* 运算符? :-)

【讨论】:

    【解决方案2】:

    首先,标准 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 );
    }
    

    【讨论】:

    • 我个人更喜欢while ( *p1 &amp;&amp; *p1 == *p2 ) {++p1, ++p2},否则,很好的答案。
    • @Superlokkus 循环可以写成 for ( const unsigned char *p1 = ( const unsigned char * )s1, *p2 = ( const unsigned char * )s2; *p1 && *p1 == *p2; ++p1, ++p2 );如您所见,循环没有正文(语句)。而且它还有一个问题:循环外需要指针p1和p2。;
    • @Superlokkus 所以让我们改变它 const unsigned char *p1 = ( const unsigned char * )s1, *p2 = ( const unsigned char * )s2; for (; *p1 && *p1 == *p2; ++p1, ++p2 );但同样,这个循环没有主体。这令人困惑。
    • @Superlokkus 要制作循环的主体,将 EXPESSION 作为 EXPRESSION STATEMENT 放置在循环之外就足够了。在这种情况下,它看起来像 char *p1 = ( const unsigned char * )s1, *p2 = ( const unsigned char * )s2;而 (; *p1 && *p1 == *p2 ) ++p1, ++p2 ;;所以我们有相同的原始循环,但循环的 init 部分和循环的表达式部分像一个语句一样放在循环之外。
    • @Superlokkus 对不起。我不认为我们可以互相说新的东西。:)
    【解决方案3】:

    您似乎希望避免使用指针算术,这很遗憾,因为这会使解决方案更短,但您的问题只是您扫描超出了字符串的末尾。添加显式中断将起作用。您的程序稍作修改:

    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】:

      这是 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

      【讨论】:

        【解决方案5】:

        您的问题是您没有检测到字符串的结尾,因此如果两个字符串在检测到任何差异之前都结束,则不返回零。

        您可以通过在循环条件中检查这个来解决这个问题:

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

        请注意,两个字符串都会被检查,因为如果最后只有一个字符串不相等,循环内的比较应该会检测到这一点。

        请注意,字符比较可能不会产生您预期的结果。一方面,它没有定义 char 是有符号还是无符号,因此您可能应该转换为 unsigned char 进行比较。

        也许更简洁的解决方案是在您检测到差异时立即返回,即直接返回 -1 而不是 -1。但这更多的是见仁见智。

        【讨论】:

        • &amp;&amp; 是多余的,现阶段你知道string1[i] == string2[i]
        • 如果字符串 1 为零且字符串 2 不为零,您将继续进入未定义的行为
        • @PeterMiehle 在这种情况下string1[i]&lt;string2[i] 将是真的,你将停止返回-1
        • @zakinster 好点,我决定跳过该解决方案并改为检查循环条件。
        • @zakinster 不完全是,你知道string1[i] 等于string2[i] 上一次迭代(如果有的话)。然而,while 语句中的第二个测试检查我们是否到达任何字符串的末尾,因此无论如何都需要它 - 字符串 "a\0z""a\0y" 应该比较相等。
        【解决方案6】:

        我的实现

        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
        

        最后一个三元操作是可选的

        当你只返回*s1 - *s2时,该函数仍然在strcmp的规则中。

        【讨论】:

        • 您正在比较 null 之后的元素。请参阅:strcmp("foobar\0b", "foobar\0a") 返回 1,应该返回 0(与标准库中的 strcmp 一样)。试试这个:while (*s1 &amp;&amp; *s1 == *s2) {s1++; s2++;}
        【解决方案7】:

        另一个优雅的(但不是最“干净的代码”)实现,带有指针。

        int a_strcmp(char* t, char* s)
        {
            for( ; *t == *s ; *s++ , *t++)
                if(*t == '\0')
                    return 0;
            return *t - *s;
        }
        

        不使用指针的版本。

        int b_strcmp(char t[], char s[])
        {
            int i;
            for(i = 0; s[i] == t[i]; ++i)
                if(t[i] == '\0')
                    return 0;
            return t[i] - s[i];
        }
        

        【讨论】:

        • 你跳过了字符串的第一个字符,所以strcmp("a", "b")会比较相等。
        • 更正了帖子,Olaf,很好,谢谢!
        • 不要在 while 条件内递增。例如。第一个i++ 将返回零/假,从而产生相同的结果,即使字符串不同strcmp("abc", "abd")。第一个实现也是如此。考虑strcmp("\0a", ""),这将在第一个字符之后中断并比较不相等,即使它应该返回零。请使用多个输入测试这两个实现,并验证它们是否按预期工作。
        • 再次感谢,使用 for 循环更改了植入,其中增量更直接。
        【解决方案8】:

        取自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 一样工作。

        【讨论】:

        • 你抄错了,漏掉了负号。
        猜你喜欢
        • 2013-11-29
        • 1970-01-01
        • 2016-04-23
        • 1970-01-01
        • 1970-01-01
        • 2021-03-22
        • 2019-07-09
        • 1970-01-01
        • 2011-02-20
        相关资源
        最近更新 更多