K& R 1.6阵列。不理解代码

时间:2016-06-18 17:48:20

标签: c

我开始阅读K& R The C programmming(第2版)一书。我被困在1.6阵列上;我似乎无法弄清楚代码的作用(即使它说它计算数字,空格和其他!)。这是代码:

#include <stdio.h>
/* count digits, white space, others */
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);
}

首先它定义了整数,(c,i,nwhite,nother); 之后,它创建一个10位数的数组,(0 -9) 之后,它将nwhite和nother设置为0。

for循环将I设置为0,i&lt; 10表示如果它更低,则加i = i + 1。 ndigit [i] = 0?我不太明白,不是我已经0了吗?

while((c = getchar()!= EOF)表示输入是什么,不是文件的末尾?。

在那之后,我有点迷路了,我不知道是什么

if (c >= '0' && c <= '9')
++ndigit[c-'0']; 

完全没有。

我不太明白为什么for(i = 0; i&lt; 10; + = i)重复了。我确实懂英语,但是一些昂贵的用词会让我感到困惑。所以,如果你不介意,请为我保持基本。我真的希望有人可以帮助我100%理解这段代码。毕竟,谁想要一个甚至无法理解代码的程序员呢? :)

1 个答案:

答案 0 :(得分:5)

让我们逐步完成代码,看看发生了什么。

main()
{
    int c, i, nwhite, nother;
    int ndigit[10];
    nwhite = nother = 0;

在第一行代码中,我们声明[0](对编译器)c, i, nwhitenother将是整数变量。在这一点上,虽然我们已经声明了这些变量,但我们没有给它们任何值。

下一行我们声明ndigit将是一个包含10个整数的数组,同样没有进行初始化,因此我们不知道这10个整数的值是什么。

在第三行中,我们将nwhitenother定义为零,换句话说,我们将它们初始化为某个值。

    for (i = 0; i < 10; ++i)
        ndigit[i] = 0;

在这个循环中,我们将变量i初始化为零,并且我们将在循环中将它递增一次,直到值变为十或更大。循环体将数组的每个元素设置为零。这是用于初始化数组元素的常用c-idiom。

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

下一个代码块执行实际计数。虽然K&amp; R中的代码在语法上是正确的,但我更喜欢用大括号括起while循环的bode,我觉得它更容易阅读,但它是个人的东西[1]。

while循环((c = getchar()) != EOF)的条件可能有点令人困惑。我们首先在括号中执行操作,即c = getchar(),它具有获取下一个字符并将其分配给变量c的效果。 (记住在C中一个字符(即char类型的变量),只是一个小整数,所以我们可以为一个整数类型指定一个字符类型)。赋值语句有一个返回值[2],因为它返回赋值运算符右侧的值,因此括号中的操作返回getchar()的值,然后将其与{{1}进行比较},如果它不等于EOF,我们输入while语句的主体。

第一个if语句检查字符是否为数字。在ASCII中,数字的值为0x30(&#39; 0&#39;)到0x39(&#39; 9&#39;),因此我们检查字符是否在该范围内。如果是,我们在EOF数组中增加适当的值。例如,假设我们已经阅读了字符&#39; 5&#39;其ASCII值为0x35。因为0x35在0x30和0x39之间,所以我们有一个数字。执行减法c - &#39; 0&#39;相当于0x35 - 0x30,等于0x05。然后我们将其用作数组的索引,并使用ndigit增加适当的值。

if-block的下一个分支,检查c是否是一个空格,即 表达式++ndigit[c-'0']检查c是否为空格,或者c是否为换行符,或者c是否为制表符。如果c是我们当时的那些字符之一 增加nwhite。

最后,如果我们没有数字或空格,则采用else分支,然后我们再增加。

c == ' ' || c == '\n' || c == '\t'

最后一段代码只打印出结果。因为我们想要查看ndigit数组的所有十个元素,我们需要再次遍历数组,因此我们使用for循环结构来查看数组的每个元素。

希望这可以解决一些问题。您可能想要尝试的是修改此代码,以便计算输入中出现的字母数。首先只是尝试和计算字母,不考虑案例,然后看看你是否可以计算大写和小写字母。

注释: [0]声明变量只是指定变量的名称和类型,因此 printf("digits ="); for (i = 0; i < 10; ++i) printf(" %d", ndigit[i]); printf(", white space = %d, other = %d\n", nwhite, nother); } 只是一个声明。我们正在向编译器提供足够的信息,它可以检查我们对x的使用情况。定义是当我们为变量赋值时,int x;是一个定义。请注意,声明和定义可以合并为一行x=5;。在汇编级别,声明会导致为变量分配存储,但不会设置存储位置包含的内容。

[1] C语法说如果有一段时间不需要大括号 它由单个语句

组成
int x = 5;

    while(n > 10)
       c--;

是等价的,我发现第二个更容易阅读。另外,C语法 如果主体由单个语句组成,那么花括号不需要if语句的主体,例如

    while(n > 10)
    {
         c--;
    }

    if(n < 10)
         n = n - 10;

是等价的。

最后,else if和end all都是if语句的一部分,所以语句

    if(n < 10)
    {
        n = n - 10;
    }

实际上是一个单一的陈述,因此不需要大括号。

另外,为了便于阅读和维护,我倾向于使用带有if / else if / else块的花括号 - 但这又是个人的想法。

[2]赋值语句的左侧返回值,因此只返回 if (c >= '0' && c <= '9') ++ndigit[c-'0']; else if (c == ' ' || c == '\n' || c == '\t') ++nwhite; else ++nother; 的简单表达式返回值。具有返回值允许我们编写像a = 10;这样的东西,其效果是将a,b和c设置为10.除了具有返回值之外,赋值运算符是右关联的,因此上面的表达式将会 解释为a = b = c = 10

-T。