不理解这个陌生的语法:arr1[ arr2[i] - 'a' ]++

Don't understand this unfamiliar syntax: arr1[ arr2[i] - 'a' ]++

我正在查看一个程序,它可以找到输入字符串的频率。比较是根据字符串的 ASCII 值与小写字母 'a' 的 ASCII 值进行的。我已经实施了;它可以工作,尽管有一个错误,但本质上,我不知道特定的代码行;

for (int i = 0; i < strlen(arr2); i++)
{
    // this line...
    arr1[ arr2[i] - 'a' ]++;
}

arr1 是 arr1[26] = {0}, 也就是说,字母表中的所有字母都被分配了一个索引,数组被初始化为零,而 arr2[] 作为函数参数,接收标准输入。

神秘的代码行是如何工作的,它在说什么?

完整代码:

#include <stdio.h>
#include <string.h>
    
#define ALEPH   26
    
void freq(char arr2[]);
    
int main ()
{
    char * str;
    
    printf("\nCharacter Frequency\n"
    "--------------------\n");
    
    // user input
    printf("\nEnter a string of characters:\n");
    fgets(str, ALEPH, stdin);
    
    freq(str);
    
    return 0;
}
    
// Function Definiton
void freq (char arr2[])
{
    // array for ascii characters initialised to 0
    int arr1[ALEPH] = {0};
    
    // scan and cycle through the input array
    for  (int i = 0; i < strlen(arr2); i++)
    {
         arr1[ arr2[i] - 'a' ]++;
    }
    
    for (int j = 0; j < 26; j++)
    {
        if ( arr1[j] != 0 )
        {
            printf("\nCharacter: %c - Frequency: %d", 'a'+j, arr1[j]);
        }
    }
    printf("\n");
}

你问的线路:

arr1[ arr2[i] - 'a' ]++;

这一行:

  • arr1是将累加直方图的数组
  • arr2 是将有助于直方图的输入字符串
  • i 是输入字符串的索引。

这可以重写为:

ch = arr2[i];
histogram_slot = ch - 'a';
arr1[histogram_slot ] = arr1[histogram_slot ] + 1;

对于输入字符串中的每个字符,从字符串中提取字符并分配给“ch”。 “ch”通过减去'a'转换为直方图数组中的索引。在第三行,histogram_slot 加一。 histogram_slot 'a' 递增 0,'b' 递增 1,'c' 递增 2,...,'z'.

递增 25

此代码中的一个严重错误是它仅适用于小写字母。大写字母、数字、标点符号、Unicode、扩展 ASCII 或不在 'a' 和 'z' 之间的任何字符都会写入意外的内存区域。充其量,这将导致意外崩溃。在中等灾难中,它会导致通过您的测试的偶发故障。在最坏的情况下,它会创建一个安全漏洞,允许某人不受控制地访问您的堆栈,从而接管线程的执行。

arr1是26个int的数组,初始化为0。其元素的索引为0..25.

arr2 被假定为仅由小写字母 'a'..'z' 组成的字符串。假设这些字符使用一种编码,其中小写字母是单字节且值是连续的,例如 ASCII(其中 a=97,...,z=122)。与这些假设不匹配的任何其他内容都将导致此代码中出现 未定义的行为

代码循环遍历arr2,对于每个字符,通过从字符的数值中减去'a'(即ASCII 97)的数值来计算索引:

'a' - 'a' = 97 - 97 = 0
'b' - 'a' = 98 - 97 = 1
...
'z' - 'a' = 122 - 97 = 25

然后代码访问该索引处的 arr1 元素,并将该元素的值递增 1。