stringstream 不会在多个调用中重置

问题描述 投票:0回答:2

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

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
继续前进并按预期取下一个名字。这是打开多个字符串流的问题吗?初始化不当?

我假设所有输入都是正确的类型,这些问题我稍后会解决。我已经阅读了几乎所有我能在该站点上找到的与该主题相关的帖子,但我似乎找不到可行的解决方案。

c++ input stringstream istringstream
2个回答
1
投票

在您的

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);


0
投票

使用

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.