如何将文件中的数据读入结构?

时间:2016-01-30 02:43:54

标签: c++

我有一个文本文件,我想读入一个结构。

Harry;3.4;3.21;2.83;3.78
Ron;2.89;2.21;2.10;3.33
Hermione;3.65;3.78;4.0;3.89
Dumbledore;2.36;2.75;3.12;3.33
Snape;3.12;2.4;2.78;3.2        

这是学生结构。

struct Student
{
string name;
double gpa[4];
double averageGPA;
};         

我已经动态分配了Student数组,现在我想从数据中读取文件。使用getline(infile, pointer[0].name, ';');将获得名字,但我无法读取数字。如果我使用getline(infile, pointer[0].gpa[0], ';');,我会收到错误消息。我认为它是因为double gpa[4]不是字符串?我怎样才能读取数据中的数据?

2 个答案:

答案 0 :(得分:1)

要读取整数,请使用operator>>

getline(infile, pointer[0].name, ';');
for (int loop = 0; loop < 4; ++loop) {
    infile >> pointer[0]. gpa[loop];
    // You now need to read the ';' off the input stream
    // Note the last number is not followed by a ';'
}

上述代码不会进行任何错误检测。你应该添加它。

通常,struct / class也可以定义自己的输入操作符。

std::istream& operator>>(std::istream& in, Student& data)
{
    // do the reading in here.
    return str;
}

完成后,您可以轻松阅读stuent个对象。

int main()
{
    Student   s1;
    std::cin >> s1;
}

答案 1 :(得分:0)

1)创建Student提取运算符

如果您要转发到对象,C ++提供了提取运算符作为封装此类功能的方法。 http://msdn.com在此处对提取运算符进行了很好的介绍:https://msdn.microsoft.com/en-us/library/k63a66ec.aspx

但从根本上说,你想写一个看起来像这样的东西:

istream& operator>> (istream& lhs, Student& rhs) {
    lhs >> ws;
    getline(lhs, rhs.name, ';');
    lhs >> rhs.gpa[0];
    rhs.averageGPA = rhs.gpa[0];

    const auto size = sizeof(rhs.gpa) / sizeof(rhs.gpa[0]);

    for(auto i = 1; i < size; ++i) {
        lhs.ignore(numeric_limits<streamsize>::max(), ';');
        lhs >> rhs.gpa[i];
        rhs.averageGPA += rhs.gpa[i];
    }
    rhs.averageGPA /= size;
}

2)使用vector<Student>而不是动态分配Student[]

与动态分配的数组相比,

vector提供了许多优势,其中最重要的是基于范围的for - 循环和iterator s。

但是在您编写了一个提取运算符之后,您还可以使用istream_iterator来构造const vector<Student>。例如:

stringstream in{"Harry;3.4;3.21;2.83;3.78\nRon;2.89;2.21;2.10;3.33\nHermione;3.65;3.78;4.0;3.89\nDumbledore;2.36;2.75;3.12;3.33\nSnape;3.12;2.4;2.78;3.2"};
const vector<Student> data{istream_iterator<Student>{in}, istream_iterator<Student>{}};

您可以看到所有这些的实际示例,包括在data范围内使用for - 循环播放:http://ideone.com/iAFE9c

3)删除Student.averageGPA

Student.averageGPA是应根据需要计算的派生数据。将其作为Student的一部分维护以询问同步问题,可能会调用不必要的计算,并使提取运算符复杂化。

您可以在C ++ 17中轻松获得初始化Student s1的平均GPA:

const auto averageGPA = accumulate(cbegin(s1.gpa), cend(s1.gpa), 0.0) / size(s1.gpa);

或者在C ++ 11中:

const auto size = sizeof(s1.gpa) / sizeof(s1.gpa[0]);
const auto averageGPA = accumulate(s1.gpa, s1.gpa + size, 0.0) / size;

但这样做的重点在于简化了提取操作符:

istream& operator>> (istream& lhs, Student& rhs) {
    lhs >> ws;
    getline(lhs, rhs.name, ';');
    lhs >> rhs.gpa[0];

    for(auto i = 1; i < size(rhs.gpa); ++i) {
        lhs.ignore(numeric_limits<streamsize>::max(), ';');
        lhs >> rhs.gpa[i];
    }
}