在C语言中统计字符串中一个字符出现的次数

44

我有一个字符串str

char *str = "100.10b.100.100";
我想要统计字符串 str 中出现的 '.' 的次数,最好是使用一行代码实现。(如果可能不要用循环)。
我的方法是使用标准的 strchr
  int i = 0;
  char *pch=strchr(str,'.');
  while (pch!=NULL) {
    i++;
    pch=strchr(pch+1,'.');
  }

3
对于口头禅包 - 你试过什么?它有什么问题没有解决?....... - KevinDTimm
@KevinDTimm:我发布了我的方法。 - Mike
6
正如 tvanfosson 指出的那样,你可以使用递归来完成这项任务,也许这就是你的老师想让你做的,但这是一种完全愚蠢的方法。对于足够大的字符串,它将导致堆栈溢出……而不是那种能为你完成作业的好的 SO,而是坏的那种!;-) - R.. GitHub STOP HELPING ICE
12个回答

92

这是我会做的方式(需要最少的变量):

for (i=0; s[i]; s[i]=='.' ? i++ : *s++);

46
我会称之为“聪明”。在编程中,“聪明”并不总是好事情。我通常更喜欢“显而易见”的方法。 - tvanfosson
6
如果您已经在增加变量s,为什么不完全使用变量i来计算'.'出现的次数?代码如下:for (; *s; i += *s == '.', s++)。 - Jake
2
@cp.engr:在这种情况下,也许我们应该将其改为(s[i] != '\0') != 0以增加清晰度?;-) - R.. GitHub STOP HELPING ICE
3
我想知道有多少人和我一样,用了一整天的时间来试图弄清这件事。 - razz
15
聪明的解决方案,但这会将指针移动到另一个位置,因此您将无法再次使用字符串s。 - smihael
显示剩余11条评论

36

好的,这是一个非循环实现(是的,它旨在作为一个玩笑)。

size_t CountChars(const char *s, char c)
{
  size_t nCount=0;
  if (s[0])
  {
    nCount += ( s[0]==c);
    if (s[1])
    {
      nCount += ( s[1]==c);
      if (s[2])
      {
        nCount += ( s[2]==c);
        if (s[3])
        {
          nCount += ( s[3]==c);
          if (s[4])
          {
            nCount += ( s[4]==c);
            if (s[5])
            {
              nCount += ( s[5]==c);
              if (s[6])
              {
                nCount += ( s[6]==c);
                if (s[7])
                {
                  nCount += ( s[7]==c);
                  if (s[8])
                  {
                    nCount += ( s[8]==c);
                    if (s[9])
                    {
                      nCount += ( s[9]==c);
                      if (s[10])
                      {
                        /* too long */
                        assert(0);
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  return nCount;
}

7
我认为你在这里将8倍增了:nCount += ( s[88]==c);。你应该编写一个C代码生成器,通过system调用cc来生成最终结果。甚至更好的做法是编写一个递归代码生成器,以避免代码生成器中的循环。 - mu is too short
4
七年后,有人对此进行了负分投票,甚至没有评论说明原因。这是一段滑稽的代码,并在开头说明了这一点。它说明了问题不切实际的可笑之处。是否有人担心这是不好的风格? - Michael J

31

看,妈妈,没有循环。

int c = countChars( s, '.' );

int countChars( char* s, char c )
{
    return *s == '\0'
              ? 0
              : countChars( s + 1, c ) + (*s == c);
}

但是,我实际上会使用循环,因为那是应该使用的正确控制结构。


2
我认为 | 应该是 :。此外,“无循环”虽然不错,但它并不像循环那样易读易维护,也不会更快。(尽管由于尾递归,它可能不会更慢。)聪明的代码并不总是好代码,特别是当它混淆了意义时。 - cdhowie
5
但是你确实在使用循环!(只是你没有使用for/while关键词)。 - user166390
1
@pst -- 不是循环,而是使用递归,这在这种情况下可能更糟糕。 - tvanfosson
1
你需要在括号中使用 *s==c。显然,+ 的优先级高于 == - R.. GitHub STOP HELPING ICE
@tvanfosson - 这很有道理。顺便说一下,这是一个可能更快的版本,因为它将字符搜索抽象成了标准库:int countChars(char *s, char c) { return (s = strchr(s, c)) ? countChars(s + 1, c) + 1 : 0 } - Chris Lutz
显示剩余16条评论

18
没有循环会很难,因为没有标准的C库函数可以完成此操作,而且您需要查看所有字符 :) 我会采取显而易见的解决方案:
int i, count;
for (i=0, count=0; str[i]; i++)
  count += (str[i] == '.');

如果必须的话,可以将实际代码的两行压缩为一行 :)


1
for (i=0; s[i]; s[i]=='.' ? i++ : s++); - R.. GitHub STOP HELPING ICE
3
那会修改s的,不过我试图不改变原始值 :) 除此之外,很好! - Fabian Giesen

6

如果你想要一个简洁的表述(其实是两个):

size_t count = 0;
while(*str) if (*str++ == '.') ++count;

这里将其简化为一个for语句,包括循环变量和输出:for (size_t i=0; s[i] || printf("%d\n", i)>INT_MAX; s[i]=='.'?i++:s++); ;-) - R.. GitHub STOP HELPING ICE

5
我仍然会将其放入一个函数中,参数化源字符串和要搜索的字符。
int count_characters(const char *str, char character)
{
    const char *p = str;
    int count = 0;

    do {
        if (*p == character)
            count++;
    } while (*(p++));

    return count;
}

只有实际可行的答案才是最好的选择...尤其是如果你喜欢易读的代码。然而,我不得不用if(strcmp(p, character))替换if (*p == character),否则它无法正常工作。 - aseq
是的,可能是我改了什么东西,没有完全复制。但我还是有一些实际用途,所以谢谢。 :-) - aseq

2

//我猜应该可以工作。一行代码,无需循环。

int countChar(char *s, char letter) {
    return ((*s) ? (((*s++ == letter)? 1:0)) + countChar (s, letter)): 0);
}

1

每次运行这段代码,Dijkstra小宝贝都会哭泣 :)

  1
  2
  3
  4 #include <ctype.h>
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <string.h>
  8
  9
 10 size_t bytewise_pop_count(
 11     unsigned char * bp, size_t l
 12 ) {
 13     if ( (bp) && (l) ) {
 14         return bytewise_pop_count(bp+1, l-1) + (bp[0] ? 1 : 0);
 15     }
 16     return 0;
 17 }
 18
 19 void mercilessly_complement_bytes(
 20     unsigned char * bp, size_t l
 21 ) {
 22 /*
 23     transform
 24         0 -> 1
 25         !0 -> 0
 26 */
 27     if ( (bp) && (l) ) {
 28         bp[0] = bp[0] ? 0 : 1;
 29         mercilessly_complement_bytes(bp+1, l-1);
 30     }
 31 }
 32
 33 void xor_bytes(
 34     unsigned char * bp1, unsigned char * bp2, size_t l
 35 ) {
 36     /* stores result in bp2 */
 37     if ( (bp1) && (bp2) && (l) ) {
 38         bp2[0] ^= bp1[0];
 39         xor_bytes(bp1+1, bp2+1, l-1);
 40     }
 41 }
 42
 43
 44 int main(int argc, char * * argv) {
 45     char c;
 46     size_t count;
 47     size_t l;
 48     char * string;
 49     char * t;
 50
 51     if (argc < 3) {
 52         fprintf(stderr,
 53             "\n"
 54             "==> not enough arguments -- need char and string\n"
 55             "\n"
 56         );
 57         return EXIT_FAILURE;
 58     }
 59
 60     c = argv[1][0];
 61     string = argv[2];
 62
 63     if ( l = strlen(string) ) {
 64         t = malloc(l);
 65         memset(t, c, l);
 66         xor_bytes(string, t, l);
 67         mercilessly_complement_bytes(t, l);
 68         count = bytewise_pop_count(t, l);
 69         free(t);
 70     } else {
 71         count = 0;
 72     }
 73
 74     if ( isprint(c) ) {
 75         printf(
 76             "\n"
 77             "==> occurences of char ``%c'' in string ``%s'': %zu\n"
 78             "\n"
 79             , c, string ? string : "<NULL>", count
 80         );
 81     } else {
 82         printf(
 83             "\n"
 84             "==> occurences of char ``%hhu'' in string ``%s'': %zu\n"
 85             "\n"
 86             , c, string ? string : "<NULL>", count
 87         );
 88     }
 89     return EXIT_SUCCESS;
 90 }

并不完全符合所要求的“一行代码(如果可能的话,不使用循环)”! - Andrew
AAAAAAAAAAAAAAAAHHH - Fractaly

1
唯一不使用循环的方法是递归。以下内容仅供娱乐,但不建议作为解决方案:
size_t CountChars(char* s, char c)
{
    return *s ? ((c==*s) + CountChars(s+1)) : 0;
}

1

我不喜欢使用goto语句,尽管如此,

    int i=0,count=0;
    char *str = "100.10b.100.100";
    a:
    if(str[i]=='.')
        count++;
    i++;
    if(str[i])
    goto a;

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