如何在C字符串中计算字符'/'的出现次数?

5

我可以如何计算C字符串中/出现的次数?

我可以这样做:

int countSlash(char str[])
{
    int count = 0, k = 0;
    while (str[k] != '\0')
    {
          if (str[k] == '/')
              count++;
          k++;
    }
    return count;
}

但这并不是一种优雅的方式;有什么改进建议吗?

3
我认为你的东西已经足够优雅了。 - P.P
1
主要的批评可能是与int countChar(char const *str, char c)相比,它具有相当专业化的接口,该函数(a)承诺不修改传递给它的字符串,并且(b)可以用于计算星号、空格等,几乎没有效率损失。如果您真的想要更少通用的接口,您可以编写一个简单的函数int countSlash(char const *str) { return countChar(str, '/'); }。如果启用了内联等功能,编译器很有可能为您优化它。 - Jonathan Leffler
优雅,可以有很多不同的方式。它可能是最短的,或者最易读的,或者最容易理解的。而最易读的,对于其他人来说也可能是最难读的。因此,“优雅”是一种主观的想法。也许你应该询问最高效的方式,就速度而言。 - ChinoCarloSedilla
4个回答

7

strchr函数可以使循环更简洁:

ptr = str;

while ((ptr = strchr(ptr '/')) != NULL)
    count++, ptr++;

我应该补充说明,我不是为了简洁而简洁,并且在所有其他条件相等的情况下,我始终会选择最清晰的表达。我发现strchr循环更加优美,但问题中的原始实现很清晰,并且存在于一个函数内部,所以我不偏向其中任何一个,只要它们都通过单元测试即可。


1
没错,但在21世纪没有好的理由编写那样的代码! - Oliver Charlesworth
4
21世纪的C编码人员会如何编写代码,@OliCharlesworth?我是一名仍在工作的20世纪C编码人员;pb2q编写的代码看起来对我来说是countSlash()函数的主体部分。 - Jonathan Leffler
1
@JonathanLeffler:我天生不喜欢过度压缩的代码,它们模拟了例如K&R所倡导的约定(在这种情况下,赋值和条件在同一行)。 当终端很小且编译器很差时,这可能是有道理的,但现在已经不再是这样了。 但显然,这是一个品味问题。 (话虽如此,我刚刚看到slashmais的答案,那是我所说的更糟糕的例子!) - Oliver Charlesworth
2
@OliCharlesworth,我真的不能说在表达式内进行分配存在问题,毕竟这是一种语言特性,而且我认为非常容易阅读和理解。另一方面,我不喜欢“过度冗长”的惯例,我发现这使得代码在快速浏览几行时难以阅读。需要来回跳跃,因为所有内容都散落在周围。不好。 :) - zxcdw
2
@OliCharlesworth:那你会写什么呢?char *ptr = strchr(str, '/'); while (ptr != NULL) ptr = strchr(ptr, '/');?这样会两次调用strchr(),违反了DRY(不要重复自己)原则。 - Jonathan Leffler
显示剩余7条评论

2

通用接口,明显的方法,适当的类型和纯粹的惯用语:

size_t str_count_char(const char *s, int c)
{
    size_t count = 0;

    while (s && *s)
         if (*s++ == c)
             ++count;

    return count;
}

奥利·查尔斯沃斯可能会对在同一行上分配和条件语句提出疑虑,但我认为它被隐藏得相当好 ;-)


我可能错了,但我认为你的循环不变式可以简化为 while (*s)。只需要在执行的最开始检查 s 不是一个 NULL 指针就可以了。 - Greg E.
@GregE.:你说得对,在这里检查NULL只需要一次。我坚信编译器比我聪明,因此我依赖编译器来优化它。这应该很容易,因为我们在这个函数中没有修改s - Philip
@Philip,可能是这样,但考虑到它是冗余的并且使循环更加昂贵,为什么不将其移动到包含的if语句中呢?顺便说一下,我注意到此页面上大多数解决方案都没有检查NULL指针就直接跳转到解引用字符串,这可能会导致未定义的行为,所以你没有做同样的事情值得赞扬。 - Greg E.

2

你的已经足够好了。也许,这样会更加美观:

int countSlash(char * str)
{
    int count = 0;
    for (; *str != 0; ++str)
    {
        if (*str == '/')
            count++;
    }
    return count;
}

0
这也能行。
int count=0;
char *s=str;
while (*s) count += (*s++ == '/');

3
为什么没有空格?为什么要使用强制类型转换?为什么不直接使用 n += (*s++ == '/'); - Jonathan Leffler
@JonathanLeffler:是的,这样会更容易看一些;强制类型转换:因为str[]是一个数组而不是字符串,这是C语言。 - slashmais
1
@slashmais,我非常确定显式转换是完全多余的。我已经很久没有在C中进行任何真正的编码了,但是据我回忆,当您传递引用数组的变量时,它会自动降级为指向该数组第一个元素的指针。因此,char str[]char *str在所有意图和目的上应该是完全可互换的。 - Greg E.
2
char *s=str; 是有效的 C 代码。你不需要进行强制类型转换。这里使用三元运算符是多余的。(*s++ == '/') 无论如何都会返回 0(假)或 1(真)。你正在做类似于 (1 || 0)?1:0 的事情。 - Jack
@Jack:谢谢,这说明C++(bool类型)在C语言中会干扰直接思考 - 我会相应地更改我的答案 :) - slashmais

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接