C语言 K&R书练习1-9:程序将其输入复制到其输出,用单个空格替换一个或多个空格的每个字符串

pprl5pva  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(101)
#include <stdio.h>

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

字符串
这段代码是如何工作的?
代码运行良好。我只需要了解它的工作原理。

qco9c6ql

qco9c6ql1#

你的方法很好,但是你必须将prevchar初始化为任何不同于' '的东西。如果你将prevchar初始化为' ',初始空格将从流中删除,这不是赋值的一部分。
以下是修改后的版本:

#include <stdio.h>

int main(void)
{
    int c, prevchar = 0;
    while ((c = getchar()) != EOF) {
        if (c != prevchar || prevchar != ' ')
            putchar(c);
        prevchar = c;
    }
    return 0;
}

字符串

  • 用单个空白替换一串空白 * 被实现为移除紧跟在另一个存储体之后的空白。

代码的逻辑是,如果从输入流读取的每个字节与前一个字节不同,或者前一个字节不是空白(空格字符' '),则将其复制到输出流。
表示为(c != prevchar || prevchar != ' ')的条件等价于

(!(c == prevchar && prevchar == ' '))


除非它与前一个字节相同并且前一个字节也是空的,否则复制可读取为c的。
将此条件表示为

(c != ' ' || prevchar != ' ')


例如:c不是空白或前一个字节不是空白。

r7knjye2

r7knjye22#

这本书在很多方面都有问题--最糟糕的问题是它积极地教导了一些糟糕的做法,比如在if语句中赋值,这反过来又是一个令人难以置信的众所周知的bug来源。这在1989年也是众所周知的糟糕做法。
但是,如果在C89编译器上执行,代码不会从main()调用未定义的行为,这是K&R的目标编译器。我们不应该编写具有未定义行为错误的代码。这在1989年也是众所周知的坏习惯。
在现代C中,我们可以跳过main()中的return 0;,但在旧的C89中从来不允许这样做。
prevchar也必须在使用前初始化。将其初始化为0EOF将有效,因为这两个都不是有效的字符串输入形式stdin
一个无bug,无不良实践,C89兼容版本的代码:

#include <stdio.h>

int main (void) 
{
  int prevchar = 0;
  for(int c=getchar(); c != EOF; c=getchar())
  {
    if (c != prevchar || prevchar != ' ')
    {
      putchar(c);
    }
    prevchar=c;
  }

  return 0;
}

字符串
说明:

  • c连续地从标准输入中逐字符阅读。它必须是int,因为常量EOFint
  • 如果遇到EOF,循环会立即中断。请注意,for循环总是在执行循环体之前检查循环条件。
  • prevchar存储前一个字符。
  • 不清楚的部分是c != prevchar,意思是:
  • 要么c是空格,要么prevchar不是,反之亦然。在任何一种情况下,它都不是一行中的两个空格。
  • 或者c不是一个空格,而prevchar是,反之亦然。在这种情况下,输入它在空格和其他字符之间进行转换,所以也不是一行中的两个空格。
  • 或者cprevchar相等,在这种情况下,一行中可能有2个空格,需要prevchar != ' '检查来排除这种情况。

为了增加可读性和减少晦涩,我们也可以这样写:

if (c == ' ' && prevchar == ' ')
  ; /* do nothing */
else
  putchar(c);


这是更清晰和自我文档化,所以它比原来的编程好得多。我们也可以在这个表达式上应用 * 德摩根定律 *,尽管我不认为它提高了可读性:

if (c != ' ' || prevchar != ' ')
  putchar(c);

相关问题