【问题标题】:Strncmp implementationstrncmp 实现
【发布时间】:2015-09-14 08:19:07
【问题描述】:

我有以下带有测试驱动程序的 strncmp 函数实现,但是无法编译。

我也不确定逻辑是否正确。这是来自我的编译器的错误消息:

警告:控制可能到达非空函数的末尾 [-Wreturn-type]

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

#undef strncmp

int strncmp(const char *s, const char *t, size_t num)
{
    for ( ; num >0;  s++, t++, num--)
        if (*s == 0)
            return 0;

    if (*s == *t) {
        ++s;
        ++t;
    }
    else if (*s != *t)
        return *s - *t;  
}

 int main ()
 {
   char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
   int n;
   puts ("Looking for R2 astromech droids...");
   for (n=0 ; n<3 ; n++)
     if (strncmp (str[n],"R2xx",2) == 0)
     {
       printf ("found %s\n",str[n]);
     }
   return 0;
 }

【问题讨论】:

  • 您的实现中至少存在三到四个错误。你为什么不去code review 让人们逐行拆开你的代码?
  • 不,@NikolaiRuhe,CodeReview 仅适用于工作代码。 SO 用于损坏的代码。
  • @ARedHerring 不确定 CodeReview 但 SO 似乎也不太合适(请参阅有关“为什么此代码不起作用?”的帮助部分)。
  • 仅仅因为它在 SO 上是题外话,不是就意味着它在 CR 上是题外话。如果这里离题,请投票关闭,但请在建议迁移之前阅读我们的帮助部分,否则用户只会在两个方面感到失望,这对任何人都没有帮助。
  • 拜托拜托拜托:总是if / else / for / while 的主体周围加上大括号({ })。这是粗心编码造成错误的主要原因之一。

标签: c string compare


【解决方案1】:

除了其他人提到的错误,you are supposed to compare the characters as unsigned char。一旦超过 ASCII-7,这一点就变得很重要,如果不这样做,您的结果将是错误的

以下是我自己的(经过测试的)实现(来自我在PDCLib 上的原始工作,即CC0 licensed)。

int strncmp( const char * s1, const char * s2, size_t n )
{
    while ( n && *s1 && ( *s1 == *s2 ) )
    {
        ++s1;
        ++s2;
        --n;
    }
    if ( n == 0 )
    {
        return 0;
    }
    else
    {
        return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
    }
}

【讨论】:

  • 应该是n &amp;&amp; *s1 ...以避免访问不应该访问的内存。
  • @chux:如果s1 没有指向一个有效的字符串,这可能是一个问题,这将是 UB 开头(7.1.4 库函数的使用 / 7.21.1 字符串函数公约 (2))。但是,是的,将n 放在首位会更可靠。那时我的设计决定是在不让代码“耍花招”的情况下实现最大性能,我认为s1 耗尽比n 运行为零的可能性更大。里程可能会有所不同。
  • strncmpComparison functionsmemcmp() 下。 s1 不需要指向有效的字符串(以空字符结尾)。传递无效的 string 指针不是 UB。只需要一个指向字符数组的有效指针 - 因此需要首先测试n
  • *(unsigned char *)s1 - *(unsigned char *)s2 优于 s1 - s2。在unsigned char 的范围与int/unsigned 相同的罕见平台上,最好使用(*(unsigned char *)s1 &gt; *(unsigned char *)s2) - (*(unsigned char *)s1 &lt; *(unsigned char *)s2) 以避免溢出。还是喜欢这个答案最好。
  • 考虑char s1[4] = {1,2,3,4}; strncmp(s1, s2, sizeof s1)。原始答案访问了s1[4],它超出了s1[] 和UB。最初传递的s1 可以使*s1 表现良好,但是增加访问它一次太远是我的cmets 关心的问题。
【解决方案2】:

control may reach end of non-void function

非 void 函数的最后一次迭代必须是返回值。 (你的函数返回一个 int)

在某些情况下,您的代码不会使用返回。你需要一个,所以试着找到哪里;)。

【讨论】:

  • 好的,那它应该返回什么?
  • "返回 *s - *t;"这将返回一个 int,所以它很好。看开天的评论。如果没有进入else,就没有返回任何东西,这是不正确的。
【解决方案3】:

查看您的代码:

 for ( ; num >0;  s++, t++, num--)



      if (*s == 0)
          return 0;

      if (*s == *t) {
          ++s;
          ++t;
      }

       else if (*s != *t)
          return *s - *t;
  1. 其实你的代码更像这样:

    for ( ; num >0;  s++, t++, num--) {
          if (*s == 0)
              return 0;
    }
    
      if (*s == *t) {
          ++s;
          ++t;
      }
    
       else if (*s != *t)
          return *s - *t;
    
  2. 你有两个“s++; p++"

查看thisthis了解更多详情

【讨论】:

    【解决方案4】:

    让我们一块一块地看

    for ( ; num >0;  s++, t++, num--)
        if (*s == 0)
            return 0;
    

    上面的循环递增 s 和 t 直到 num 为 0 或直到 s 指向 0,在这种情况下你返回 0。如果 num > strlen(s) 你总是返回 0。

    现在我们已经完成了循环。让我们看看接下来会发生什么......

    if (*s == *t) {
        ++s;
        ++t;
    }
    else if (*s != *t)
        return *s - *t; 
    

    如果 s 和 t 都指向具有相同值的字符,则它们都递增,否则返回它们所指向的值的差值。请注意,如果它们相等,则您永远不会显式返回值。这就是编译器出错的原因。

    那么你需要修复算法,目前这个算法是完全错误的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-14
      • 2017-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多