结构体向量:C++中添加元素

4

我正在从文件中读取我的结构体,并希望将它们添加到结构体向量中。 以下是代码的样子和工作方式:

    typedef struct
{
    int ID;
    string name;
    string surname;
    int points;
}
Student;

int main()
{
    ifstream theFile("test.txt");
    std::vector<Student*> students;

    Student* s = new Student();

    while(theFile >> s->ID >> s->name >> s->surname >> s->points)
    {
        studenti.push_back(s); // here I would like to add this struct s from a file
    }

// here I want to print each struct's values on the screen, but the output is always ONLY last struct N times, and not all of them, each only once


    std::vector<Student*>::const_iterator it;
    for(it = students.begin(); it != students.end(); it+=1)
    {
        std::cout << (*it)->ID <<" " << (*it)->name << " " << (*it)->surname <<" " << (*it)->points <<endl;
    }

我该怎么做,才能将我的结构体添加到向量中,并正常地打印它们(这个打印只是一个检查,确保结构体已正确加载到向量中)?


2
为什么要使用 typedef - Kerrek SB
1
文件格式是什么?每个学生的名字都恰好由两个单词组成吗? - Kerrek SB
请注意,您没有一个结构体向量,而是一个指针向量。所有这些指针都指向同一个对象... - juanchopanza
4个回答

9

下面是使用现代C++编写的代码示例:

#include <string>
#include <istream>
#include <vector>

struct Student
{
    int ID;
    std::string name;
    std::string surname;
    int points;

    Student(int i, std::string n, std::string s, int p)
    : ID(i), name(std::move(n)), surname(std::move(s)), points(p) {}
};

std::vector<Student> read_students(std::istream & is)
{
    std::vector<Student> result;

    std::string name, surname;
    int id, points;

    while (is >> id >> name >> surname >> points)
    {
        result.emplace_back(id, name, surname, points);
    }

    return result;
}

使用方法:

#include <fstream>
#include <iostream>

int main()
{
    std::ifstream infile("test.txt");
    auto students = read_students(infile);

    // ...
}

1
我尝试像你上面的例子一样使用emplace_back()来添加一个具有四个字段的结构体,但在编译过程中我收到了“没有匹配的构造函数”错误,所以你提供的示例似乎是不正确的。 - kometen
2
@kometen:你说得对,Student需要一个适当的构造函数。我添加了一个。或者,你可以说result.push_back({id, name, surname, points});,这样你就不需要为那个版本添加构造函数了。 - Kerrek SB
非常优雅的解决方案。谢谢。 - kometen
1
@kometen:没问题 :-) 感谢您指出这个错误!就记录而言,我认为在这种情况下push_back和聚合初始化是更好的解决方案;我不会改变类定义来适应插入。当类已经具有适当的构造函数时,您可以使用emplace。 - Kerrek SB

8

你的错误在于使用指针

std::vector<Student> students;

Student s;
while(theFile >> s.ID >> s.name >> s.surname >> s.points)
{
    students.push_back(s);
}

现在它将正常工作。

问题是您一直在重复使用相同的指针。因此,您最终得到一个指向同一对象的指针向量。这将具有最后读取的学生的值。

似乎选择复杂的替代方案而不是正确的简单方案是初学者的普遍特征,因此我很想知道为什么您选择使用指针。


我认为如果之后需要在程序中调用该列表的方法,使用指针会更好。但是我对指针不太熟悉,这只是一个想法。实际上,我并不确定指针的优缺点。 - Whizzil
你可以在不使用指针的情况下调用列表上的方法。这没有任何区别,例如 students[i].some_method(); - john

0

由于您想在向量中存储指向学生的指针而不是学生本身。

Student* s = new Student();

while(theFile >> s->ID >> s->name >> s->surname >> s->points)
{
    students.push_back(s); // here I would like to add this struct s from a file
}

你只分配了一个学生对象,在每次循环时都在重复读取同一个对象。

相反,你应该在每次循环中分配一个新的学生对象并将数据读入新的已分配内存中。

Student* s;
int tmpId, tmpPoints;
string tmpname, tmpsur;

while(theFile >> tmpId >> tmpname >> tmpsur >> tmpPoints)
{
    s = new Student();

    s->ID = tmpId ;
    s->name = tmpname;
    s->sur = tmpsur ;
    s->points= tmpPoints;

    studenti.push_back(s); // here You push a pointer to the newly allocated student
}
else
{
    // There is error reading data
}

不要忘记在你不再需要该向量时删除每个学生。

0

你的代码无法运行,因为你只有一个学生对象,并在每次赋值时覆盖其成员。解决方法是每次创建一个新的学生对象,并将指向它的指针传递给你的向量:

std::vector<Student*> students;
int tmpId, tmpPoints;
string tmpname, tmpsur;

while(theFile >> tmpId >> tmpname >> tmpsur >> tmpPoints)
{
    Student* s = new Student();
    s->ID = tmpId ;
    s->name = tmpname;
    s->sur = tmpsur ;
    s->points= tmpPoints;

    students.push_back(s); // push a pointer to new student object
}
else
{
    // ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接