c – 吃了EOF后重复使用std :: cin

unix命令wc具有以下功能:

$wc - - -
aaa bbb ccc<EOF>
0 3 11 -
aaa bbb ccc<EOF>
0 3 11 -
aaa bbb ccc<EOF>
0 3 11 -
0 9 33 total

每个< EOF>表示< C-d>将EOF输入stdin的键序列.然后wc能够拿起这个EOF.

我正试图在C中实现这一点.一个常见的建议是clear()和ignore()的组合.

char c;
while (std::cin >> c) { ... }

std::cin.clear();
std::cin.ignore();

while (std::cin >> c) { /* never executed */ }

我也试过std :: cin.peekg(std :: cin.beg),这也行不通.

解决方法:

在戴维斯的耐心帮助下,我了解了使用Ctrl D完成的输入输入与我不知道的此处文档之间的区别. (我向戴维斯鲱鱼致敬.)

有一次,我得到了它在C中的其余部分非常简单,如我的MCVE所示.

line-count.cc:

#include <fstream>
#include <iostream>
#include <string>

unsigned process(const std::string &fileName, std::istream &in)
{
  unsigned nLines = 0;
  if (in.bad()) {
    std::cerr << "ERROR: Cannot open '" << fileName << "'!\n";
    return 0;
  }
  for (std::string buffer; std::getline(in, buffer); ++nLines);
  std::cout << "File: '" << fileName << "', " << nLines << " counted.\n";
  return nLines;
}

int main(int argc, char **argv)
{
  unsigned nLines = 0;
  for (int i = 1; i < argc; ++i) {
    const std::string arg = argv[i];
    if (arg == "-") {
      nLines += process(arg, std::cin);
      std::cin.clear();
    } else {
      std::ifstream fIn(arg.c_str());
      nLines += process(arg, fIn);
    }
  }
  std::cout << "Total: " << nLines << " counted.\n";
  return 0;
}

cygwin64编译和测试:

$g++ -std=c++11 -o line-count line-count.cc

$./line-count line-count.cc - line-count.cc -
File: 'line-count.cc', 32 counted.
1
2
3
File: '-', 3 counted.
File: 'line-count.cc', 32 counted.
1
2
3
File: '-', 3 counted.
Total: 70 counted.

$

所以,它确实是std::cin.clear()的技巧,它重置了输入流中的EOF标志,并且可以从/ dev / stdin再次读取.

在OP的情况下,在std :: cin.clear()之后的std::cin.ignore()是恕我直言.它丢弃重新启用的标准输入的第一个字符,这使得以下处理错误(通过不计算第一个字符).

戴维斯(再次)提出了一个简短而明显的解释,我用我的话说:

使用CtrlD,标准输入在下次尝试读取时接收EOF;并将其记忆在其内部标志中.然而,标志可以重置.如果没有任何进一步的输入,则下一次读取尝试将失败,否则,输入可以继续.

可能是,值得强调std :: ios中的内部EOF标志.如果没有std::cin.clear(),即使有更多输入,读取尝试也会失败.只要内部std :: stream标志不能产生良好状态,即使可能成功,也不会在较低级别执行读取尝试.

上一篇:C++ I/O流技术


下一篇:没有“转到”的C用户输入限制和正确的重试