C代码如何运作?

Har*_*dal 1 c arrays

简介:我正在关注K&R的"C编程语言",我遇到了以下代码的一部分,我无法理解.

代码:

#include <stdio.h>

int main()
{
    int c, i, nwhite, nother;

    int ndigit[10];

    nwhite = nother = 0;
    for (i = 0; i < 10; i++)
    {
        ndigit[i] = 0;
    }

    while ((c = getchar()) != EOF)
    {
        if (c >= '0' && c <= '9')
            ++ndigit[c - '0'];
        else if (c == ' ' || c == '\n' || c == '\t')
            ++nwhite;
        else
            ++nother;
    }

    printf("digits = ");

    for (i = 0; i < 10; i++)

    {
        printf(" %d", ndigit[i]);
    }

    printf(", white space = %d, other = %d\n", nwhite, nother);
}
Run Code Online (Sandbox Code Playgroud)

样本输入:

sample text for stackoverflow
try 123
123456789
Run Code Online (Sandbox Code Playgroud)

输出:

digits =  0 2 2 2 1 1 1 1 1 1, white space = 7, other = 29
Program ended with exit code: 0
Run Code Online (Sandbox Code Playgroud)

我理解代码在做什么,但我无法理解它是如何做的.为什么我们++ndigit[c - '0'];在代码中使用了?

Who*_*aig 5

您似乎遇到最麻烦的算法部分是数字频率的计算.具体地说,其中使用的索引机制.

该算法通过使用计数器阵列来工作.具体来说,这个:

int ndigit[10];
Run Code Online (Sandbox Code Playgroud)

是存储计数的地方.最初,此数组使用后续for循环填充零:

for (i = 0; i < 10; i++)
{
    ndigit[i] = 0;
}
Run Code Online (Sandbox Code Playgroud)

在处理期间,从stdin读取每个字符.测试的字符在以下集合之一:

  • 大于或等于文字字符的东西'0',与文字字符相等或相等'9'.在这种情况下,它被认为是数字字符.稍后会详细介绍.
  • 可以是空格,换行符或制表符之一的东西.这些被认为是空格字符.
  • 还要别的吗

第一个是算法中最复杂的部分.字符(和字符文字)是整数类型.因此,它们的行为与上述相同,您可以对它们执行各种数学运算.但这些操作必须对语言标准规定的某些保证有意义.

语言标准规定所有数字字符代码在任何符合标准的平台上的表示都应是连续的.标准ASCII字符编码使用48到57的字节值(十六进制0x30到0x39).有关ASCII编码的全部内容,请参阅asciitable.com.对于备用编码,这些值可能不同.例如,标准EBCDIC(此时主要用于IBM minis和大型机)使用值240-249.虽然这看似微不足道,但对于您呈现的代码的工作原理非常重要.在所有情况下(ASCII或其他情况),数字字符是连续的(全部在一起并且是连续的).语言标准要求这样做.

那为什么要这么重要?这很重要,因为它允许你做这样的事情(在这里使用ASCII作为例子):

int x = '5' - '0';
Run Code Online (Sandbox Code Playgroud)

结果x将是5.注意我并没有'5'(人物); 我说整数 5.那是因为实际的ASCII编码意味着你实际得到的整数计算是:

//      '5'  '0'
int x = 53 - 48;
Run Code Online (Sandbox Code Playgroud)

通常你会听到人们谈论"幻数编程",这通常就是一个例子.当你看到代码说:

if (c == 48)
    do something with the char because it's a zero character
Run Code Online (Sandbox Code Playgroud)

不要那样做.保持代码清洁并使用文字常量.它更容易阅读

if (c == '0')
Run Code Online (Sandbox Code Playgroud)

意图更清晰.

无论如何,这对你的代码有何影响?好吧,它在这里播放:

if (c >= '0' && c <= '9')
    ++ndigit[c - '0'];
Run Code Online (Sandbox Code Playgroud)

这使用ASCII编码等价物,实际上看起来像这样:

if (c >= 48 && c <= 57)
    ++ndigit[c - 48];
Run Code Online (Sandbox Code Playgroud)

正如我之前所说,不要写那样的代码.这只是为了展示实际发生的事情.字符文字实际上是int值,这些值参与一些数学计算计数器数组中的索引.

例如,假设c'7'(注意:字符,而不是整数).然后这个:

if (c >= '0' && c <= '9')
    ++ndigit[c - '0'];
Run Code Online (Sandbox Code Playgroud)

相当于:

if ('7' >= '0' && '7' <= '9')
    ++ndigit['7' - '0'];
Run Code Online (Sandbox Code Playgroud)

最终相当于:

if (55 >= 48 && 55 <= 57)
    ++ndigit[55 - 48];
Run Code Online (Sandbox Code Playgroud)

而且由于55-48是简单的7,这意味着最终的索引是:

    ++ndigit[7]; 
Run Code Online (Sandbox Code Playgroud)

对输入文件中的所有数字字符进行此操作,最后,显示每个数字字符的累计次数.

我希望能把它搞清楚.其余的我认为你理解.