0

I'm not quite getting a structure search. I have a task, I need to search for students by full name, year of birth, group number or course number. I can search by group number or course number, but the search by full name and date of birth is problematic.

Here are my code and my input file. (I'm sorry if my code is unprofessional, I'm just learning and I need to pass this task, but I'm having no luck and I have no one to turn to for help)

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

struct Student
{
    string name;
    string yearob;
    int course;
    int group;
};
ostream& operator<<(ostream& out, const Student obj)
{
    out << obj.name << " " << obj.yearob << " " << obj.group << " " << obj.course;
    return out;
}

int main()
{
    setlocale(LC_ALL, "");
    int search = 0;
    string name_s, yearob_s;
    int course_s, group_s;
    int chek = 1;
    while (chek == 1)
    {
        cout << "Enter 1 to start, 0 to exit > ";
        cin >> chek;
        switch (chek)
        {
        case(0):
            break;
        case(1):
        {
            int leng = 0;
            string s;
            ifstream fle("input.txt");
            while (getline(fle, s))
            {
                leng += 1; 
            }
            Student* list = new Student[leng];
            int a = 0;

            fle.close();
            ifstream file("input.txt");

            string ss, buff;
            while (getline(file, s))
            {
                buff.assign(s);
                list[a].course = buff[0] - '0';
                buff.erase(0, 2);

                ss += buff[0];
                ss += buff[1];
                list[a].group = stoi(ss);
                ss.clear();
                buff.erase(0, 3);

                for (int i = 0; i < 4; i++)
                    list[a].yearob += buff[i];
                buff.erase(0, 5);

                list[a].name.assign(buff);
                a += 1;
                buff.clear();
            }
            cout << "What parameter should be used to find students: 1 - by name, 2 - by year of birth, 3 - by course, 4 - by group number: ";
            
            cin >> search;
            switch (search) {
            case(1):
                cin >> name_s;
                for (int i = 0; i <= leng; i++) {
                    if (list[i].name.find(name_s, 10)) {
                        cout << list[i].name << ", " << list[i].course << " course, " << list[i].group << " group, " << list[i].yearob << " year of birth; " << endl;
                    }
                    else {
                        continue;
                    }
                }
            case(2):
                cin >> yearob_s;
                for (int i = 0; i <= leng; i++) {
                    if (list[i].yearob.find(yearob_s, 5)) {
                        cout << list[i].name << ", " << list[i].course << " course, " << list[i].group << " group, " << list[i].yearob << " year of birth; " << endl;
                    }
                    else {
                        continue;
                    }
                }
            case(3): {
                cin >> course_s;
                for (int i = 0; i <= leng; i++) {
                    if (course_s == list[i].course) {
                        cout << list[i].name << ", " << list[i].course << " course, " << list[i].group << " group, " << list[i].yearob << " year of birth; " << endl;
                    }
                    else {
                        continue;
                    }
                }
            }
            case(4):
                cin >> group_s;
                for (int i = 0; i <= leng; i++) {
                    if (group_s == list[i].group) {
                        cout << list[i].name << ", " << list[i].course << " course, " << list[i].group << " group, " << list[i].yearob << " year of birth; " << endl;
                    }
                    else {
                        continue;
                    }
                }
            }


                file.close();
                continue;
            }
        default:
        {
            cout << "Input error" << endl;
            continue;
        }
        }
        }
    }

Input file:

2 01 1999 Cody Hoyt
2 01 2002 Danielle Robyn Diaz
3 01 1999 Mayra Marie Collins
2 05 2000 Marc Nunez
4 05 2000 Tricia Gilmore
5 04 2001 Dale Lucas
1 01 1998 Ruby Merritt
2 01 2001 Tabitha Jenkins
4 02 1995 George Kris Oneill
2 03 1999 Bonnie Blair
  • did not you notice that you have a problem with the string comparison? – Sherif O. Apr 02 '22 at 08:30
  • Yes, I noticed, but I posted all the code so you can see everything – krakozyabrr Apr 02 '22 at 08:42
  • did you notice you have a problem with the strings *in general* ? It isn't coincidental that both of the fields you say you're having problems with are reading formatted input, ex: `cin >> name_s`. If you type `Cody Hoyt` in for that prompt your going to get `Cody` and the remainding data will remain in the input stream. So, not only are you not getting the full name, you're leaving the input stream polluted with data. – WhozCraig Apr 02 '22 at 08:48
  • Yes, I noticed. I replaced `cin` with `getline(cin, name_s)`, but now input is skipped and the input file in the console is printed. Where do I need to write `cin.ignore();`? – krakozyabrr Apr 02 '22 at 09:05
  • 1
    For mixing `getline` and `operator>>`, please see [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction) – BoP Apr 02 '22 at 09:45

1 Answers1

0

Just maybe a shorter version of your code. I provide it not as a solution to your main question (because the following code is pretty advanced), but as an example of how you could avoid repeating code and making big nested constructions.

Here I moved out the code of reading students from a file into a separate function, and inside it should easily read each student using operator>> from a file. Similarly you can define operator<< to specify in which format you want students to be printed.

The repetitive code of printing filtered students is moved into a single function, that iterates all students and prints only pass a given test. You then give this test as a lambda function in each branch of switch operator

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <functional>

using namespace std;

struct Student
{
    string name;
    string yearob;
    int course;
    int group;
};
ostream& operator<<(ostream& out, const Student& stud)
{
    out << stud.name << ", " << stud.course << " course, " << stud.group << " group, " << stud.yearob << " year of birth; " << endl;
    return out;
}

istream& operator>>(istream& in, Student& stud)
{
    in >> stud.course >> stud.group >> stud.yearob >> stud.name;
    return in;
}

vector<Student> read_students_file(const string& filename) {
    vector<Student> students;
    ifstream file(filename);
    while (file)
    {
        students.push_back({}); // insert empty student
        file >> students[students.size() - 1]; // fill student
    }
    file.close();
    return students ;
}

void print_filtered(const vector<Student>& students, function<bool(const Student&)> should_print) {
    for (const Student& student : students) {
      if (should_print(student)) {
          cout << student;
      }
    }
}

int main()
{
    setlocale(LC_ALL, "");
    while (true)
    {
        cout << "Enter 1 to start, 0 to exit > ";
        int check;
        cin >> check;
        if (check == 0) {
          break;
        } else if (check != 1) {
          continue;
        }
        
        vector<Student> students = read_students_file("input.txt");
            
        cout << "What parameter should be used to find students: 1 - by name, 2 - by year of birth, 3 - by course, 4 - by group number: ";
        int search_variant;
        cin >> search_variant;
        switch (search_variant) {
          case(1): {
            string find_name;
            cin >> find_name;
            print_filtered(students,
              [&](auto& student){ return student.name == find_name; });
            break;
          }
          case(2): {
            string find_yearob;
            cin >> find_yearob;
            print_filtered(students,
              [&](auto& student){ return student.yearob == find_yearob; });
            break;
          }
          case(3): {
            int find_course;
            cin >> find_course;
            print_filtered(students, 
              [&](auto& student){ return student.course == find_course; });
            break;
          }
          case(4): {
            int find_group;
            cin >> find_group;
            print_filtered(students,
              [&](auto& student){ return student.group == find_group; });
            break;
          }
          default: {
            cout << "Input error" << endl;
            continue;
          }
        }
    }
}
Alexey S. Larionov
  • 6,555
  • 1
  • 18
  • 37