【问题标题】:How to calculate the frequency of a character in a string in C如何在C中计算字符串中字符的频率
【发布时间】:2021-02-17 20:51:59
【问题描述】:

我找到了计算字符串中字符频率的代码,但是,它们都使用同一行代码,没有解释它的含义。有人可以请教我吗?

这是一个例子:

int c = 0, count[26] = {0}, x;

while (string[c] != '\0') {
/** Considering characters from 'a' to 'z' only and ignoring others. */

  if (string[c] >= 'a' && string[c] <= 'z') {
     x = string[c] - 'a';
     count[x]++;
  }

我知道循环将遍历字符串直到它到达末尾。 我也得到了 if 语句,因为它只将它限制在 a 和 z 之间。 但是,我不知道x = string[c] -'a' 在做什么,为什么要减去'a'? 我也不明白count[26]的目的是什么。

我从这里得到这个程序:

https://www.programmingsimplified.com/c-program-find-characters-frequency

任何帮助将非常感谢。

【问题讨论】:

    标签: c ascii


    【解决方案1】:

    TL;DR利用了 ASCII 表。

    代码只接受从az的字符:

    if (string[c] >= 'a' && string[c] <= 'z') 
    

    因此它创建了一个包含 26 个位置的数组(count[26])来存储这些相同字符的频率。以下

       x = string[c] - 'a';
    

    string[c] 转换为 int;事实可以用来利用ASCII table

    根据 ASCII 表,字母 'a' 到 'z' 分别由从 97112int 值表示。因此,由于 C 中的数组以 0 开头,我们需要将 97 元素从 string[c] 返回的值向左移动,即:

     x = string[c] - 97;
    

    可以表示为

     x = string[c] - 'a';
    

    有了这个技巧如果string[c]是'a'那么:

     x = 'a' - 'a';
    

    转换为x = 97 - 97,然后是x = 0;因此,

    count[x]++;count[0]++;

    将数组count 的位置0 加1,该位置被“保留”到字母'a'。同样的逻辑适用于从“a”到“z”的所有其他字母。

    但请记住,并引用Eric Postpischil

    C 实现中使用的字符代码不一定有 所有字母连续。 ASCII 确实很常见,但不是 标准要求。

    因此,如果您的编码是 ASCII,此解决方案将有效。

    【讨论】:

      【解决方案2】:

      count[26] 是频率表。 count[0]a 的出现次数。 count[1]b 的出现次数等...

      count 数组初始化为全零值

      count[26] = {0}
      

      虽然不在字符串的末尾。请记住,C 字符串总是以空字符 (\0) 结尾。

      while (string[c] != '\0') {     
      

      判断 string[c] 处的字符是否介于 a 和 z 之间

        if (string[c] >= 'a' && string[c] <= 'z') {
      

      将此字符的 ascii 值(介于 97 到 122 之间)标准化为 0 到 25 之间的值。a 在数学表达式中计算时为 97。

           x = string[c] - 'a';
      

      使用上面计算的x 值,将其用作count 表的索引 将 count[x] 中的任何值增加 1。

           count[x]++;
      

      此代码示例中缺少的是 c 递增 1 以使 string[c] 引用字符串中的下一个字符的地方。

      【讨论】:

        【解决方案3】:

        在 ASCII 数据库中,'a' 到 'z' 有从 0x61 到 0x7A 的连续数字代码。参看。 man ascii。 因此,如果你减去 'a' 的值,你会得到 0 到 25 之间的数字。这个数字是 count[] 表中的一个索引。

        【讨论】:

          【解决方案4】:

          count[26]是一个26个整数的数组,每个整数代表string中从'a''z'的小写字母的计数

          count[0]'a' 的计数器,count[1]'b' 的计数器等等...

          x = string[c] - 'a' 计算并分配给xstring[c] 找到的字符的索引0-25。 简化:请记住 'a' 是整数 ascii 值 97 十进制。 'a' 的减法是将所有索引从 'a' 减少到 'z'count[] 数组所需的 0 到 25 之间的值。

          【讨论】:

            【解决方案5】:

            首先,该代码取决于连续表示的字符 'a''z',这很常见但不能保证。

            第二,

            int c = 0, count[26] = {0}, x;
            
            while (string[c] != '\0') {
            /** Considering characters from 'a' to 'z' only and ignoring others. */
            
              if (string[c] >= 'a' && string[c] <= 'z') {
                 x = string[c] - 'a';
                 count[x]++;
              }
            

            有几个问题,我想说的是更清楚

            #include <ctype.h>
            
            // multiple variables on one line is ***very*** bug prone
            // so don't do it
            int c = 0;
            int count[26] = {0};
            
            // set the input - unsigned is important
            unsigned char *string = ...;
            
            // loop until the character pointed at by string is '\0'
            while ( *string )
            {
              // islower() returns non-zero only if the unsigned char value
              // passed is a lower-case letter.
              //
              // If the input int value  can't be represented as an unsigned
              // char the results are undefined behavior (because tolower() 
              // actually takes an int argument.)
              //
              // signed char will be sign-extended when passed as an int argument
              if ( islower( *string ) )
              {
                 // get the "index" of the lower-case letter
                 // a -> 0, b -> 1, z -> 25
                 // depends on a-z being consecutive - not necessarily true
                 int x = *string - 'a';
            
                 // increment the number of times this lower-case character
                 // is in this string
                 count[x]++;
              }
            
              // go to the next character in the string
              string++;
            }
            

            请注意,我在减少使用的行数方面付出了零努力。将代码塞进更少的行数不会带来任何好处,但会使代码更难阅读,因此更容易出错。

            对字符串中的字符进行计数的更好方法:

            #include <limits.h>
            
            void countChars( unsigned char *string )
            {
                int counts[ UCHAR_MAX ] = { 0 };
            
                while ( *string )
                {
                    counts[ *string ]++;
                    string++;
                }
            }
            

            如果要计算小写字符:

            #include <limits.h>
            
            void countLowerCaseChars( unsigned char *string )
            {
                int counts[ UCHAR_MAX ] = { 0 };
            
                while ( *string )
                {
                    counts[ tolower( *string ) ]++;
                    string++;
                }
            }
            

            【讨论】:

              猜你喜欢
              • 2017-04-19
              • 2011-10-06
              • 1970-01-01
              • 2016-05-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-25
              • 1970-01-01
              相关资源
              最近更新 更多