计算换行符、空格和制表符

3
这个问题来自K&R的第20页:编写一个程序来计算空格、制表符和换行符。以下是我的尝试:
#include <stdio.h>

int main()
{
  int character, whitespace = 0;

  printf("Enter some text, and press Ctrl-d when you're done.\n\n");

  while((character = getchar() != EOF) {
    if(character == (' ' || '\n' || '\t')) {
      ++whitespace;
    }
  }

  printf("\nYour text contains %d spaces, tabs, and lines.\n", whitespace);

  return 0;
}

程序出现问题了。无论用户的文本中有多少个空格、制表符和换行符,它总是给出0作为答案。有人能看出问题所在吗?还有一件奇怪的事情:我必须按两次Ctrl-d才能注册。我不知道为什么。 谢谢!


3
你的while语句缺少右括号;这可能是复制粘贴错误,因为你说程序能够编译和运行。请确保缺失的右括号在getchar()之后而不是在EOF之后,否则会导致结果不正确。 - James McNellis
你可能需要按两次“Ctrl-d”,因为在输入后你没有按回车键。Shell会缓存你的输入,直到它看到一个换行符。 - Lucas
6个回答

18
if(character == (' ' || '\n' || '\t'))

测试 character 是否等于 (' ' || '\n' || '\t') 的结果(结果为1,表示 || 的结果为真)。你需要分别对三个可能的值进行测试,例如:

if(character == ' ' || character == '\n' || character == '\t')

1
扩展 - 这是一种英语速记,在大多数编程语言中并不适用。(a == b) || (a == c) 不等同于 (a == (b || c)) - 后者通常是一个错误。请注意,你想要的 (b || c) 的语义是构建一个列表 - 在 Python 中,你可以写成 if a in [b, c, d] :,但它仍然不只是你想要的条件表达式的速记。 - user180247

3
你可能遇到的问题之一是你的条件。
尝试类似这样的语句:
if (character == '\n' || character == ' ' || character == '\t') {
    ++ whitespace;
}

1

你的代码问题在于 if(character == (' ' || '\n' || '\t')) 这个语句。语句 (' ' || '\n' || '\t') 相当于 32 || 13 || 9(每个字符都被其等效的 ASCII 值替换),这相当于 1,因为在 C/C++ 中任何非零的东西都被视为 true,所以实际上你正在执行 if(character == 1)。现在我认为你可以修复你代码中的问题。

此外,书上说要分别计算空格、制表符和换行符的数量,而你试图计算总数,所以可以像这样做。

if(character == ' ')
  ++blanks;

if(character == '\t')
  ++tabs;

if(character == '\n')
  ++newlines;

如果您想要一个完整的解决方案,这里有一个我很久以前写的。
#include <stdio.h>

int main(void)
{
  int blanks, tabs, newlines;
  int c;


  blanks = 0;
  tabs = 0;
  newlines = 0;

  do {
      c = getchar();
      if(c == ' ') {
          ++blanks;
      }
      else if(c == '\t') {
         ++tabs;
      }
      else if(c == '\n') {
         ++newlines;
      }
  }
  while(c != EOF)

  printf("Blanks: %d\nTabs: %d\nLines: %d\n", blanks, tabs, newlines);
  return 0;
}

1

您while语句中的圆括号有误,应该如下:

while( (character = getchar()) != EOF) 

你将测试getchar() != EOF的值分配给了字符,无论实际读取了什么字符,它都是1。


0
以上示例在技术上是正确的。它只会在调用EOF(文件结束)指示器后打印值。然而,我认为有一个更好的解释来解决这个练习(1.8),所以让我提出一个替代方案。以下代码将会在每行之后直接打印新行、制表符和空格。
#include <stdio.h>
#define EOL '\n'

/* Excercise 1.8 - K&R's book - 2nd edition. */
main()
{
    int c, newlines, tabs, blanks;

    newlines = 0;
    tabs = 0;
    blanks = 0;

    while ((c = getchar()) != EOF)
    {
        if (c == '\n')
            ++newlines;
        else if (c == '\t')
            ++tabs;
        else if (c == ' ')
            ++blanks;

        if (c == EOL) {
        printf("Lines: %d\nTabs: %d\nBlanks: %d\n", newlines, tabs, blanks);
        }
    }
}

0

isspace将根据您的系统作为宏或函数提供,使您无需猜测在您的环境中可能构成空格的内容。严格来说,它可能是您系统上的以下所有字符。GNU C肯定这样认为。

' '
    space
'\f'
    formfeed
'\n'
    newline
'\r'
    carriage return
'\t'
    horizontal tab
'\v'
    vertical tab

这是如何进行测试的。

 #include <ctype.h>

  while((character = getchar() != EOF) {
    if (isspace(character)) whitespace++;
  }

这解决了一个不同的问题(它计算超出问题中的字符)。-1 表示未阅读标准文档 - isspace 被定义为返回恰好该字符集合,以及其他可能在 C 区域设置之外的区域设置中的字符(但从不更少)。 - R.. GitHub STOP HELPING ICE
虽然我同意它解决了一个不同的问题(一个超集合被问到的问题),但我并不认为这对健康有害,而是可能对初学者C程序员有所帮助——也许鼓励一些超越所提出的问题的思考。你怎么能得出我的答案表明我没有阅读标准文档的结论更加好奇呢?事实上,能够在没有证据的情况下得出某件事情没有发生的结论相当有趣。也许你可以详细说明一下你是如何得出这样一个新颖的结论的?我建议给这种粗俗的争论打-1分。 - bjg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接