else if (state == OUT) 在 C 字数统计中的作用

Role of else if (state == OUT) in C word count

我正在按照《The C Programming Language》- K&R 一书学习 C; 我发现自己卡在了对else if (state == OUT):

的作用的理解上
#define IN 1
#define OUT 0

main () 
{
    int c, nw, state; 
    
    state = OUT;
    nw = 0;
    while ((c = getchar()) != EOF) {
        if (c == ' ' || c == '\n' || c == '\t')
            state = OUT;
        else if (state == OUT) {
            state = IN;
            ++nw;
        }
    }
    printf ("%d", nw);
}

在字数统计程序中,我的意思是,在我阅读它的方式中,一定有我做错的地方,因为我无法理解为什么这会产生差异,从简单的 else,因为 state = OUT已经是默认条件;但实际上我观察到它确实如此,因为如果我只写 else 那么语句 state = IN; ++nw 将计算字符而不是单词;

从我的阅读方式来看,循环是说对于每个输入字符(存储在变量 c 中),如果它是一个 space、一个换行符或一个制表符,那么它就是值为零,其他所有内容都将为 1,所以我看不出它是如何将字符分组为单词的,因为 state 在循环之前已经 OUT,那么 else if (state == OUT) 是如何得到将字符组合成一个单词的程序?

我想了一个通宵,但我的思想和书上都找不到答案

此语句正在检查字符 (c) 值: if (c == ' ' || c == '\n' || c == '\t')

如果任何字符 (c) 是 space 或换行符或制表符,则 state 值更改为 OUT.

每当字符 (c) not 是 space 时,此语句 else if (state == OUT) 正在检查 state 的值, 换行符或制表符。

程序假设所有单词都由 space、换行符或制表符分隔,并且至少有一个字符长。

:;,.?!等标点字符作为单词的合法字符包含在内。

使用getchar确保至少读取一个字符。 该程序将在检测到文件结尾字符时完成,即没有进一步的输入。

第一个不是 space、换行符或制表符的字符会增加字数。

要计算单词数,我们要增加计数,++nw,每个单词只增加一次。

如果我们写:

        if (c == ' ' || c == '\n' || c == '\t')
            state = OUT;
        else {
            state = IN;
            ++nw;
        }

然后 ++nw 将在每次 c 不是 white-space 字符 space、换行符或制表符之一时执行。但是,通过写:

        if (c == ' ' || c == '\n' || c == '\t')
            state = OUT;
        else if (state == OUT) {
            state = IN;
            ++nw;
        }

那么++nw不会在我们已经在word中时执行(状态为IN)。它只会在我们用完一个单词(状态为 OUT)并进入一个新单词(因为 c 不是 white-space 字符之一)时执行。因此,++nw 仅在我们开始一个新单词时执行,而不是针对单词中的每个字符执行。

cccc cc    c c  cccccc cc
^    ^     ^ ^  ^      ^
    |  |    | |       |  |

这是计算字数的两种方法 - 只有转换才算数。

从几何角度看,这很简单直观:每个 c 的左边都有一个白色的 space。

但是如果你单步(一次,盲目地)遍历每个元素,你只需要存储最后一个字符,它对应于“left”。这个最小的内存使这个算法成为一个状态机。

当你打一个字母时,如果你从一个单词的外部来,你只计算它,但同时将状态设置为内部,所以下一个字母不会被计算在内。下一个 space 然后将触发器设置为“OUT”。

此程序通过对具有两个状态的非常简单的状态机建模来计算单词数:

OUT: We have not read a character that is part of a word
 IN: We have read a character that is part of a word

字数由我们从OUT状态转换IN状态的次数决定。给定像 "This is a test" 这样的输出,转换的工作方式如下:

This   is a     test
^+++v--^+v^v----^+++

其中+表示IN状态,-表示OUT状态,^表示从OUT过渡到IN,而v表示从INOUT的过渡。字数等于我们看到的次数^.

为了知道我们是否正在从 OUT 状态转换到 IN 状态,我们必须检查 state 的当前值,当我们看到一个非空白字符;因此,

else if (state == OUT)

作为备用分支而不是普通的 else。否则我们会为每个非空白字符递增 nw,而不是在从 OUTIN 的过渡时递增。