Max Max - 2 months ago 29
C++ Question

Segmentation fault in cross-linked vectors

I'm trying to have a vector of students and a vector of universities, where each student has a list of universities he is applying to and each university has a list of students, that applied.
But when I run the code, "Segmentation fault: 11" happens. Can you, please, help me understand, where I'm doing wrong.

struct Student;

struct Univercity
{
std::string name;
int vacancies;
std::vector<Student *> students;

Univercity(std::string name,
int vacancies)
: name(name),
vacancies(vacancies) {}
};

struct Student {
std::string name, surname;
int d, m, y;
int points;
std::vector<Univercity *> univercities;

Student(std::string name,
std::string surname,
int d, int m, int y, int points,
std::vector<Univercity *> univercities)
: name(name),
surname(surname),
d(d), m(m), y(y),
univercities(univercities) {}
};

void input(std::vector <Student> *students,
std::vector <Univercity> *univercities) {
int n;
std::cin >> n;
for (int i = 0; i < n; i++) {
std::string name;
int vacancies;
std::cin >> name >> vacancies;
univercities->push_back(Univercity(name, vacancies));
}
std::cin >> n;
for (int i = 0; i < n; i++) {
std::string name, surname;
int d, m, y, points;
int k;
std::vector<Univercity *> applications;
std::string uni_name;
std::cin >> name >> surname >> d >> m >> y >> points >> k;
for (int j = 0; j < k; j++) {
std::cin >> uni_name;
for (auto u : *univercities) {
if (u.name == uni_name) {
applications.push_back(&u);
break;
}
}
}
students->push_back(Student(name, surname, d, m, y,
points, applications));
}

}

int main() {
std::vector <Univercity> univercities;
std::vector <Student> students;
input(&students, &univercities);
for (auto s : students) {
std::cout << s.surname << " " << s.univercities.size() << "\n";
for (auto u : s.univercities) {
std::cout << u->name << " " << u->vacancies << "\n";
}
}
}


Sample input:

3
MSU 1
HSE 2
MIPT 100
5
Ivan Ivanov 1 1 1900 100 2 MSU HSE
Petr Petrov 2 1 1900 90 2 MSU HSE
Alexander Sidorov 3 1 1900 110 2 MIPT HSE
Ivan Petrov 3 1 1900 100 3 HSE MSU MIPT
Petr Ivanov 4 1 1900 80 1 HSE

Answer

When you read the input you have:

for (auto u : *univercities) {
    if (u.name == uni_name) {
        applications.push_back(&u);
        break;
    }
}

In the ranged based for loop u is a copy of the element in the vector. Thus the adresses you push into the vector are invalid once you leave the loop. Use

for (auto& u : *univercities) { //...

to use references and avoid making copies.