c++ stringstream在几个调用之间不重置

kpbwa7wx  于 2023-03-09  发布在  其他
关注(0)|答案(2)|浏览(130)

我试图从一个代表学生的文件中加载输入。每个学生都有一个名字和分数列表,如下所示:

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在Classroom::read中的for循环调用之间 * 没有 * 重置。
这意味着main函数的输出为:

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继续下去,并按照预期的那样取下一个名称。这是打开多个字符串流的问题吗?不正确的初始化?
我假设所有的输入都是正确的类型,这些问题我将在以后修复。我已经阅读了几乎每一个帖子,我可以找到这个网站上与这个主题有关,但我似乎找不到一个工作的解决方案。

sxissh06

sxissh061#

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.push_back(s);,而不是执行students.insert(students.end(), s);

tvokkenx

tvokkenx2#

使用std::stringstreamstd::istreamstd::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;
}

相关问题