c++ - 在清除 istream 之前我不需要取消它吗?

标签 c++ string iostream cin

问题的简短版本

如果我像这样读取数据:

    while (in >> x) {
      hw.push_back(x);
    }
    // clear the stream so that input will work for the next student
    in.clear();

哪里instd::istream , xdoublehwvector<double> 。我是否不需要放回导致我跳出 while 循环的任何读取尝试?否则,我的下一篇文章不会是in吗?跳过一些数据?

完整问题

我正在尝试读取包含字符串和一系列数字的文本文件。我正在将此数据处理为一个包含该数据的成员属性的结构。

输入数据如下: Moore 75 85 77 59 0 85 75 89

此数据代表学生的姓名、期末考试成绩、期中考试成绩和一些作业。

要读取此类数据,我有以下内容:

#include <boost/format.hpp>
#include <iostream>
#include <string>

using std::istream;
using std::vector;
using std::cout;
using std::string;
using std::cin;

struct Student_info {
  std::string name;
  double midterm, final;
  std::vector<double> homework;
};

istream& read(istream&, Student_info&);
istream& read_hw(istream&, vector<double>&);

istream& read(istream& is, Student_info& s) {
  // Read and store th studen's name and midterm and final exam grades
  is >> s.name >> s.midterm >> s.final;

  read_hw(is, s.homework); // read and store all the student's homework grades
  return is;
}

istream& read_hw(istream& in, vector<double>& hw)
{
  if (in) {
    // get rid of previous contents
    hw.clear();

    // read homework grades
    double x;
    while (in >> x) {
      hw.push_back(x);
    }
    // clear the stream so that input will work for the next student
    in.clear();
  }
  return in;
}

简而言之,如果我的理解正确的话,我首先读名字,然后读两遍(期末考试和期中考试),然后不管有多少作业。

我知道何时停止阅读 vector<double>家庭作业成绩如下:

    while (in >> x) {
      hw.push_back(x);
    }
    // clear the stream so that input will work for the next student
    in.clear();

这对我来说看起来完全合理,但是当我读入一系列数据行时,数据无法正确读入。

例如,使用以下输入:

Moo 100 100 100 100 100 100 100 100
Moore 75 85 77 59 0 85 75 89
Norman 57 78 73 66 78 70 88 89

我得到以下输出:

Name: Moo, Midterm: 100, Final: 100, Num HW: 6
Name: Moore, Midterm: 75, Final: 85, Num HW: 6
Name: orman, Midterm: 57, Final: 78, Num HW: 6

请注意,这个名字是orman,而不是Norman。缺少 N。这不是一个错字,这就是我想要理解的问题。

在我看来,我需要“unget”,尽管当我尝试直接调用in.unget()时它不会改善事情。

如果有人想在自己的手中尝试一下,下面是一些完整的输入数据和驱动程序的完整源代码:

完整输入数据

Moo 100 100 100 100 100 100 100 100
Moore 75 85 77 59 0 85 75 89
Norman 57 78 73 66 78 70 88 89
Olson 89 86 70 90 55 73 80 84
Peerson 47 70 82 73 50 87 73 71

Russel 72 87 88 54 55 82 69 87
Thomas 90 96 99 99 100 81 97 97
Vaughn 81 97 99 67 40 90 70 96
Westerly 43 98 96 79 100 82 97 96


Baker 67 72 73 40 0 78 55 70
Davis 77 70 82 65 70 77 83 81
Edwards 77 72 73 80 90 93 75 90
Franklin 47 70 82 73 50 87 73 71

Jones 77 82 83 50 10 88 65 80
Harris 97 90 92 95 100 87 93 91
Smith 87 92 93 60 0 98 75 90
Carpenter 47 90 92 73 100 87 93 91

Fail1 45 55 65 80 90 70 65 60
Fail2 55 55 65 50 55 60 65 60

驱动程序完整源码

#include <boost/format.hpp>
#include <iostream>
#include <string>

using std::istream;
using std::vector;
using std::cout;
using std::string;
using std::cin;

struct Student_info {
  std::string name;
  double midterm, final;
  std::vector<double> homework;
};

istream& read(istream&, Student_info&);
istream& read_hw(istream&, vector<double>&);

istream& read(istream& is, Student_info& s) {
  // Read and store th studen's name and midterm and final exam grades
  is >> s.name >> s.midterm >> s.final;

  read_hw(is, s.homework); // read and store all the student's homework grades
  return is;
}

istream& read_hw(istream& in, vector<double>& hw)
{
  if (in) {
    // get rid of previous contents
    hw.clear();

    // read homework grades
    double x;
    while (in >> x) {
      hw.push_back(x);
    }
    // clear the stream so that input will work for the next student
    in.clear();
  }
  return in;
}

int main() {

  vector<Student_info> students;
  Student_info record;
  string::size_type maxlen = 0;

  while (read(cin, record)) {
    // find length of longest name
    cout << boost::format("Name: %1%, Midterm: %2%, Final: %3%, Num HW: %4%\n") % record.name % record.midterm % record.final % record.homework.size();
    students.push_back(record);
  }

  return 0;
}

使用完整的输入数据,输出如下所示(注意许多名称不正确):

Name: Moo, Midterm: 100, Final: 100, Num HW: 6
Name: Moore, Midterm: 75, Final: 85, Num HW: 6
Name: orman, Midterm: 57, Final: 78, Num HW: 6
Name: Olson, Midterm: 89, Final: 86, Num HW: 6
Name: rson, Midterm: 47, Final: 70, Num HW: 6
Name: Russel, Midterm: 72, Final: 87, Num HW: 6
Name: Thomas, Midterm: 90, Final: 96, Num HW: 6
Name: Vaughn, Midterm: 81, Final: 97, Num HW: 6
Name: Westerly, Midterm: 43, Final: 98, Num HW: 6
Name: ker, Midterm: 67, Final: 72, Num HW: 6
Name: vis, Midterm: 77, Final: 70, Num HW: 6
Name: wards, Midterm: 77, Final: 72, Num HW: 6
Name: ranklin, Midterm: 47, Final: 70, Num HW: 6
Name: Jones, Midterm: 77, Final: 82, Num HW: 6
Name: Harris, Midterm: 97, Final: 90, Num HW: 6
Name: Smith, Midterm: 87, Final: 92, Num HW: 6
Name: rpenter, Midterm: 47, Final: 90, Num HW: 6
Name: l1, Midterm: 45, Final: 55, Num HW: 6
Name: l2, Midterm: 55, Final: 55, Num HW: 6

更新1

我尝试添加 in.seekg(-1, in.cur);打破以下 while 循环后:

    double x;
    while (in >> x) {
      hw.push_back(x);
    }

    // Going to try and get the istream back to where it was when I broke out of the while loop.
    in.seekg(-1, in.cur);

    // clear the stream so that input will work for the next student
    in.clear();

认为这会让我回到导致我跳出 while 循环的原因。但仍然无法正确读取学生姓名

更新2

我发现这里有一个几乎相同的问题:

Why is istream.clear() removing part of my strings while reading doubles and strings?

然而,接受的解决方案并没有解释为什么这里所做的事情是错误的——它只是提供了一种解决方法。

更新3

我很欣赏所有的解决方法,但考虑一下这个更有针对性的问题,为什么后续的每一行都没有在这里或那里缺少一个字母?只有某些行可以。

最佳答案

奇怪的提取原因是字母 ABCDEFINP 可以出现在 double 中,而其他字母则不能。请参阅strtof spec详细信息。

这是没有前瞻的流 I/O 的一个基本问题。该标准(粗略地说)指定继续提取,直到找到目标类型中不能出现的字符,然后尝试转换提取的内容。多年来,对该规范进行了各种调整(包括更改 double 型的有效字符列表),但没有真正的解决方案。

没有规定在转换失败时放回字符,您将不得不使用不同的提取方法。正如另一个答案中所建议的:由于您的输入是面向行的(即换行符很重要),因此最好使用面向行的读取函数来读取一行,然后解析一行。您使用 >> 直到错误的方法无法在换行符处中断(该运算符将所有空格视为相同)。

关于c++ - 在清除 istream 之前我不需要取消它吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59811568/

相关文章:

c++ - 如何编译包含多个源文件的项目?

c - 递归strcpy函数

c++ - 打印 unique_ptr 到 cout

c++ - 选择要输入的流

C++继承 - 将 parent 更改为祖 parent

c++ - Qt 捕获复选框的信号以执行操作

C# String.Format() 返回错误字符

ruby - Ruby 中带有未知标点符号的字符串拆分

c++ - 为什么在 C++ 中使用 cin、cout 或 %I64d 优于 %lld 说明符?

c++ - 代码 : How to address dynamic Variables?