我正在尝试从代表学生的文件中加载输入。每个学生都有一个名字和分数列表,如下所示:
Name John Wayne
Scores 100 90 80 100 0
Name Bob Dwight
Scores 0 0 10 100
Name Dummy Student
Scores 0 0
我正在通过这样的类结构阅读这篇文章。教室对象保留所有学生的列表。
class Student
{
string first_name;
string last_name;
vector<int> quizzes;
public:
void read(istream & in){
string line;
// Name initialization
getline(in, line);
stringstream namereader(line);
string word;
namereader >> word; // Go past "Name"
namereader >> word;
first_name = word; // Second word in a line is firstname
namereader >> word;
last_name = word; // Third word in a line is lastname
// Quizzes
getline(in, line); // line after name contains quiz scores
stringstream quizreader(line);
quizreader >> word; // Go past "Quiz"
int quizgrade;
while(quizreader >> quizgrade){ // Read quiz scores and insert
quizzes.insert(quizzes.end(), quizgrade);
}
// Putting quizreader.str(""), quizreader.clear() does not work
//Empty Line between each student
getline(in, line);
}
void print(ostream & out) const{
out << "Name " << first_name << " " << last_name << endl;
out << "QZ Ave: " << endl;
for (int i : quizzes){
cout << i << " ";
}
cout << endl;
}
friend ostream & operator <<(ostream &out, const Student & student){
student.print(out);
return out;
}
friend istream & operator >>(istream &in, Student & student){
student.read(in);
return in;
}
};
教室:
class Classroom{
vector<Student> students;
public:
void print(ostream & out) const{
for (Student s : students){
out << s << endl;
}
}
void read(istream & in){
Student s;
while (in >> s){
students.insert(students.end(), s);
}
}
friend ostream & operator <<(ostream &out, const Classroom & cl){
cl.print(out);
return out;
}
friend istream & operator >>(istream &in, Classroom & cl){
cl.read(in);
return in;
}
};
主要功能:
int main(){
ifstream in("classroom.txt");
Classroom cl;
in >> cl;
cout << cl;
return 0;
}
当我尝试打印出来时,我注意到我的 stringstream 确实 not 在 Classroom::read 中的 for 循环完成的调用中重置。
这意味着主函数的输出是:
John Wayne
Scores 100 90 80 100 0
Bob Dwight
Scores 100 90 80 100 0 0 0 10 100
Dummy Student
Scores 100 90 80 100 0 0 0 10 100 0 0
我已经尝试使用 .clear() 和 .str("") 清除我所有的字符串流。它们不起作用,无论我将它们放在 read() 中的哪个位置以及以何种顺序放置。令我好奇的是,
quizreader
保留了之前的所有数字,但是 namereader
继续前进并按预期取下一个名字。这是打开多个字符串流的问题吗?初始化不当?
我假设所有输入都是正确的类型,这些问题我稍后会解决。我已经阅读了几乎所有我能在该站点上找到的与该主题相关的帖子,但我似乎找不到可行的解决方案。
在您的
Classroom::read
成员函数中,您构造一个 Student
对象,该对象可重复用于读取每个学生记录:
void read(istream & in){
Student s;
while (in >> s){
students.insert(students.end(), s);
}
}
问题是在
Student::read
函数中,您为每个学生重复使用 vector<int> quizzes;
成员,但您永远不会 .clear()
或在学生之间清空它。您不断附加测验分数。这解释了你的输出。
快速修复,对您所写的内容进行最少的更改,是在阅读测验分数之前致电
quizzes.clear();
。这确保向量在读取新值之前为空。
注意:当在
std::vector
的末尾添加一个值时,您可以直接说 students.insert(students.end(), s);
而不是执行 students.push_back(s);
。
使用
std::stringstream
、std::istream
和std::getline
会使事情不必要地复杂化。你可以简单地使用std::istream
而不使用任何其他东西。只有你需要做额外的状态管理。
至于
quizzes
中的保留值,您可以在Classroom::read()
中稍微改变一下阅读逻辑。
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// Name ... Scores ... Name ... Scores ...
class Student
{
string first_name;
string last_name;
vector<int> quizzes;
public:
friend istream & operator >>(istream &in, Student & student){
student.read(in);
return in;
}
void read(istream& in)
{
string token;
int state = 0; // 0 - name, 1 - scores
int name_cnt = 0;
while (in >> token)
{
if (token.empty())
continue;
if (state == 1 && token == "Name")
{
break;
}
// cout << token << '\n';
if (token == "Name")
{
state = 0;
continue;
}
else if (token == "Scores")
{
name_cnt = 0;
state = 1;
continue;
}
if (state == 0)
{
if (name_cnt == 0)
first_name = token;
else
last_name = token;
name_cnt++;
}
else if (state == 1)
{
quizzes.push_back(std::stoi(token));
}
}
cout << first_name << ' ' << last_name << '\n';
for (auto x : quizzes) cout << x << ' '; cout << '\n';
}
};
class Classroom
{
public:
void read(istream & in){
while (true)
{
Student s;
if (in >> s)
students.push_back(s);
else
break;
}
}
private:
friend istream & operator >>(istream &in, Classroom & cl){
cl.read(in);
return in;
}
vector<Student> students;
};
int main()
{
ifstream in("sample.txt");
if (!in.is_open())
{
return 1;
}
Classroom C;
C.read(in);
return 0;
}