我不明白这段代码是如何工作的

I don't understand how how this code works

我正在做 K&R 书中的练习 1-9,在尝试寻找解决方案时遇到了这段代码:

int main()
{
    int c;
    while ((c = getchar()) != EOF) {
        if (c == ' ') {
            while ((c = getchar()) == ' ');
            putchar(' ');
            if (c == EOF) break;
        }
        putchar(c);
    }
}

为什么即使我输入了一个字母,第一个if语句仍然有效。据我了解,它只会在我输入的字符为空白时执行 space? 顺便说一下,这个练习是让一个程序将多个连续的空白 space 替换为一个。

此程序打印除空白字符 ' ' 之外的任何输入字符,直到用户中断输入。

在这个 while 循环中

while ((c = getchar()) == ' ');

读取每个空白字符但不输出。而循环后只输出一个空白字符

putchar(' ');

即程序将用户输入的字符序列中相邻的空白字符去掉,只留下一个空白字符。

只要输入流没有结束(EOF = 文件结束),它就会循环。

如果输入的字符是space,它将忽略任何后续的spaces,只打印一个space。

否则输出输入的字符

我已经格式化并注释了代码。希望这会有所帮助。代码实际上隐藏了所有 stdin 中的 space 序列变成一个 space:

 "123    456 a  b c  " -> "123 456 a b c "

代码:


int main() {
    int c;
 
    /* we read stdin character after character */
    while ((c = getchar()) != EOF) {
        /* if we have read space */   
        if (c == ' ') {
            /* we skip ALL spaces */
            while ((c = getchar()) == ' ')
                ; /* skipping ALL spaces: we do nothing */

            /* and then we print just ONE space instead of many skipped */
            putchar(' ');

            /* if we at the end of stdin, we have nothing more to print */
            if (c == EOF) 
                break;
        }

        /* we print every non space character */
        putchar(c);
    }
}
int main()
{
    int c;
    while ((c = getchar()) != EOF) {

对于输入的每个字符...

        if (c == ' ') {

...如果字符是 space...

            while ((c = getchar()) == ' ');

... 这个循环会跳过第一个之后的所有 space... 看右边的分号,它读取字符,检查它是 space , 而 对它什么都不做。 这样写是一件非常棘手的事情,因为通常认为循环 body 将是下面的下一个语句, 虽然它根本没有 body 。在 while 循环之后,你可以假设让你进入循环的条件为假,所以我们有一些正确的断言:在 c 中肯定没有 space 存储(它可以仍然是 EOF,这不是一个字符,所以我们需要在打印之前对其进行测试,然后在下一条语句之后进行下一步)

            putchar(' ');

... 循环后,只输出一个 space ,对应于您在问题中提到的第一个 if 语句中测试的那个。认为 c 不是 space 字符(所以我们不能 putchar(c);),因为我们跳过所有 space 直到 none 仍然存在。它仍然可以是一个 EOF 指标,在下面检查。

            if (c == EOF) break;

如果字符不是 space,它只能是 EOF 指示符。在那种情况下,我们需要跳出循环,这样我们就不会在下一条语句中打印它...

        }
        putchar(c);

... 因为我们一直在读取 c 中的字符,直到我们得到一个非 space (也不是 EOF 指示符,因为我们在上面的循环中case) 无论如何我们都需要打印那个字符。此 putchar(c); 语句将始终打印一个 non-space 字符。它在 if 语句之外,因为必须对所有最初为非 spaces 的字符和 spaces.[=35= 序列之后的字符执行此操作]

    }

...如上,我们可以假设循环的测试条件为假,所以这里我们可以确保c得到了EOF(但只是因为break 循环内的语句也发生在 c == EOF).

}

瞧瞧!!!

备注

while trying to find solutions I came across this code:

最后一点,如果您 post 尝试编写解决方案,而不是通过搜索找到已经制定的解决方案,那对您来说会更好。您将学到更多关于编程的知识,而不是谷歌搜索,恕我直言,谷歌搜索不是您的主要兴趣。