【问题标题】:Counting the number of times a character occurs in a string in C计算字符在C中的字符串中出现的次数
【发布时间】:2011-09-08 13:45:23
【问题描述】:

我是 C 新手,我正在开发自己的 explode 类似函数。我正在尝试计算指定字符在字符串中出现的次数。

int count_chars(char * string, char * chr)
{
    int count = 0;
    int i;

    for (i = 0; i < sizeof(string); i++)
    {
        if (string[i] == chr)
        {
            count++;
        }
    }

    return count;
}

它每次都返回 0。谁能解释一下为什么? :)

【问题讨论】:

  • 不出所料,我收到此代码的编译器警告。那应该告诉你出了什么问题以及在哪里(只有其中一件是错的,但仍然如此)。编译时收到警告了吗?

标签: c arrays string explode


【解决方案1】:

您的代码存在无可救药的缺陷。以下是它应该的样子:

int count_chars(const char* string, char ch)
{
    int count = 0;
    int i;

    // We are computing the length once at this point
    // because it is a relatively lengthy operation,
    // and we don't want to have to compute it anew
    // every time the i < length condition is checked.
    int length = strlen(string);

    for (i = 0; i < length; i++)
    {
        if (string[i] == ch)
        {
            count++;
        }
    }

    return count;
}

See this code run on example input.

这是你做错的地方:

  1. 既然你想找到一个字符,第二个参数应该是一个字符(而不是char*),这在后面会有影响(见#3)。
  2. sizeof(string) 不会给你字符串的长度。它给出了架构中指针的大小(以字节为单位),它是一个常数(例如,在 32 位系统上为 4)。
  3. 您正在比较一些不是内存地址的值与chr 指向的内存地址。这是比较苹果和橙子,总是会返回false,所以if 永远不会成功。
  4. 您想要做的是将一个字符 (string[i]) 与函数的第二个参数进行比较(这就是为什么那个也是char 的原因)。李>

上述的“更好”版本

下面的评论者已正确识别出原始答案的某些部分,这些部分不是 C 语言的常用处理方式,可能导致代码缓慢,并且可能在(不可否认的特殊情况)情况下出现错误。

由于我相信 count_chars 的“正确”实现对于在 C 中迈出第一步的人来说可能过于复杂,我将在此处附加它并保持最初的答案几乎完整。

int count_chars(const char* string, char ch)
{
    int count = 0;
    for(; *string; count += (*string++ == ch)) ;
    return count;
}

注意:我故意这样写循环是为了说明在某个阶段你必须在什么是可能的和什么是可取的之间划清界限。

See this code run on example input.

【讨论】:

  • 这段代码太可怕了;原则上它在每次迭代中调用strlen,使一个简单的O(n) 任务变成O(n²)!如果一个好的编译器可能能够优化它,如果它确定字符串在循环中没有改变,但正确的循环条件是用简单的string[i]!=0 替换i&lt;strlen(string)。另外,icount 应该是 size_t 而不是 int,否则很长的字符串会有溢出的危险。
  • @R..:我同意你所有有根据的反对意见(我真诚地希望任何现代编译器都会优化strlen 调用)。请考虑到我正在回复一个新手,我不想废弃他们的所有代码,这会让他们更难理解他们做错了什么以及为什么做错了。恕我直言,上面的代码虽然有细微的缺陷,但却是通往知识之路的合理垫脚石。谢谢。
  • @Rob:目前的版本是否令人满意,或者你觉得它可以使用一些扩展?
  • 即使观众忽略了 O(n) 与 O(n²) 的讨论,这也不是教授非常糟糕的做法的借口,这些做法会导致 O(n) 循环变为 O(n²) )。新程序员应该知道测试string[i]!=0惯用在 C 中循环字符串。
  • @Jon:当然。如果你不打算学习 C 的习语,那么学习 C 是没有意义的,因为用不同语言的习语编写 C 只会给你两全其美(所有危险C 和其他语言的所有低效率)。我会考虑循环一个字符串,直到你遇到空终止,这是用 C 编写自己的字符串处理代码的最重要的习惯用法之一(而不是仅仅进行库调用)。
【解决方案2】:

您可能希望使用实际获取string 长度的函数,而不是sizeof

sizeofget the size of the datatype。它将返回字符串的长度。 strlen 将返回字符串的长度。

【讨论】:

    【解决方案3】:

    这是C!它的设计很简洁!

    int count_chars(const char* string, char ch)
    {
      int c = 0;
      while (*string) c += *(string++) == ch;
      return c;
    }
    

    更新

    我将尝试解释它是如何工作的:

    int c = 0;
    

    这将是已找到的匹配数的计数。

    while (*string)
    

    这是循环控制语句,只要条件为真,就会继续迭代循环。在这种情况下,条件是*string。在 C 中,字符串存储为“空终止”,这意味着字符串的最后一个字符是值为 0 的字符(“\0”)。 *string 计算指针指向的字符。如果 C 中的表达式求值为任何非零值,则为“真”,如果求值为零,则为“假”。 *string 是一个表达式,所以 *string 指向的任何非零字符都是 true,而字符串末尾的 '\0' 是 false。因此,如果*string 指向字符串的末尾,这将终止。

    *(string++)
    

    这是一个计算指针指向的值的表达式。 ++ 是一个后增量,因此指针的值向前移动了一个位置,即它指向字符串中的下一个字符。请注意,表达式的值与 *string 的值在计算后的值不同,因为指针已移动。

    *(string++) == ch
    

    这是一个比较表达式,它将*string 的值(更新之前)与ch 的值进行比较。在 C 中,其结果是一个整数(C 中没有 bool 类型),如果表达式为真,则值为 '1',如果表达式为假,则值为 '0'。

    c += *(string++) == ch;
    

    我们知道+= 后面的位如果是我们要查找的字符,则为“1”,否则为“0”。 += 是以下的简写:

    c = c + (*(string++) == ch);
    

    所以如果找到匹配的字符,它将增加计数。

    在这种特殊情况下,+= 语法几乎没有优势,但如果c 更复杂,比如*(variable [index].structure_member [index2]),那么它只会被评估一次。

    末尾的; 标志着语句的结束,因为while 之后没有{,它也标志着while 循环的结束。

    【讨论】:

    • 我不知道你在这里做了什么。
    • @Rob:我已经添加了一些解释性说明。
    • 哇,很好的解释。我唯一不喜欢的是它的可读性,但我想任何有经验的 C 程序员都能轻松阅读它?
    【解决方案4】:

    正如大家告诉你的答案,

    1)你不能使用大小而是strlen(string)。他们已经告诉你原因

    2)我想大家在这里都漏掉了,你使用的第二个参数是char指针。但是每个人都告诉你让它成为chr,但如果你还想这样做。

    然后在循环中应该是

    if ( string(i)== *chr ) \\ not just ch remember you declared it as a pointer
                          ch gives the address but you want the character so use *ch
    

    您也可以使用 strchr 函数。

       int count_chars (char *string, char ch)
           {
             int i;
            if(string=strchr(string,'s'))++i;
                while (string!=NULL)
                   if(string=strchr(string+1,chr)
                   ++i;
                  return i;
            }
    

    【讨论】:

      猜你喜欢
      • 2023-02-04
      • 2011-04-21
      • 1970-01-01
      • 2014-04-24
      • 1970-01-01
      • 2020-02-21
      • 2012-02-12
      相关资源
      最近更新 更多