C语言如何计算字符串中某个字符出现的频率

How to calculate the frequency of a character in a string in C

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

这是一个例子:

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

while (string[c] != '[=10=]') {
/** 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

如有帮助将不胜感激。

在ASCII数据库中,'a'到'z'有0x61到0x7A的连续数字编码。比照。 man ascii。 因此,如果你减去 'a' 的值,你会得到从 0 到 25 的数字。这个数字是 count[] table.[=11 中的一个索引=]

TL;DR 是利用了ASCII table.

代码只接受从az的字符:

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

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

   x = string[c] - 'a';

string[c]转换为int;可用于利用 ASCII table.

的事实

根据 ASCII table,字母 'a' 到 'z' 由 97112int 值表示,分别。因此,因为 C 中的数组以 0 开头,我们需要将 97 个元素从 return 的值向左移动 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:

The character codes used in C implementations do not necessarily have all the letters consecutively. ASCII does and is very common, but not required by the standard.

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

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

count 数组初始化为全零值

count[26] = {0}

虽然不在字符串的末尾。请记住,C 字符串始终以空字符 ([=21=]).

结尾
while (string[c] != '[=11=]') {     

判断字符串[c]中的字符是否在a和z之间

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

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

     x = string[c] - 'a';

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

     count[x]++;

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

count[26]是一个包含26个整数的数组,每个整数代表string

中从'a''z'的小写字母的个数

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

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

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

第二,

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

while (string[c] != '[=10=]') {
/** 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 '[=11=]'
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++;
    }
}