0

This is all my code I want to sort the records when display all students using option 2 in the main menu this code returning me the data as it was saved means unsorted.

#include<iostream>
#include<fstream>
#include<iomanip>
#include<vector>
using namespace std;



class student
{
    int Idnum;
    char Name[25];
    char Course[30];
    int Result;

public:
    void getdata();
    void showdata() const;
    void show_tabular() const;
    int getIDNum() const;
};

void student::getdata()
{
    cout << "\nEnter student's ID Number: ";//prints Enter student's ID Number
    cin >> Idnum;
    cout << "\n\nEnter student's Name: ";//prints Enter student's Name
    cin.ignore();//to ignore from the input buffer
    cin.getline(Name, 25);
    cout << "\nEnter student's Course: ";//prints Enter student's Course
    cin >> Course;
    cout << "\nEnter student's Result: ";//prints Enter student's Result
    cin >> Result;

}

void student::showdata() const
{
    cout << "\nID Number: " << Idnum;//prints ID Number
    cout << "\nName: " << Name;//prints Name
    cout << "\nCourse: " << Course;//prints Course
    cout << "\nResult: " << Result;//prints Result
}

void student::show_tabular() const
{
    cout << Idnum << setw(6) << " " << Name << setw(20) << Course << setw(20) << Result << setw(4) << endl;
}

int  student::getIDNum() const
{
    return Idnum;
}



void SaveStudent();
void displayAll();
void Searchdisplay(int);
void modifyStudent(int);
void deleteStudent(int);
void DisplayResult();

This is the code for creating a student.dat file if it does not exist here and if will exist then write a new student record but this will not sort the records as I want.

void write_student()//to create students record
{
    student st;
    ofstream outFile;
    ifstream inFile;
    outFile.open("student.dat", ios::binary | ios::app);//opens file student.dat
    st.getdata();
    //cout << st.getIDNum();
    if (inFile.seekg(reinterpret_cast<char *> (&st)))
    {

    }
    outFile.write(reinterpret_cast<char *> (&st), sizeof(student));//writes the file
    outFile.close();//closes the file
    cout << "\n\nStudent record Has Been Created ";
    cin.ignore();
    cin.get();
}

This is the place where I am showing my student's records but this will show unsorted records and I want it in a sorted way means ascending order by roll no of students.

void display_all()//to display the student record
{
    student st;
    ifstream inFile;
    inFile.open("student.dat", ios::binary);//opens file student.dat
    if (!inFile)
    {
        cout << "File could not be open !! Press any Key...";
        cin.ignore();//to ignore from the input buffer
        cin.get();//to access the char
        return;
    }
    cout << "\n\n\n\t\tDISPLAY ALL RECORD !!!\n\n";

    while (inFile.read(reinterpret_cast<char *> (&st), sizeof(st)))
    {   
        st.showdata(); //function to show data on screen
        cout << "\n\n====================================\n";
    }
    inFile.close();//closes the file
    cin.ignore();
    cin.get();
}



void display_sp(int n)//to search for student record
{
    student st;
    ifstream inFile;
    inFile.open("student.dat", ios::binary);//opens file student.dat
    if (!inFile)
    {
        cout << "File could not be open !! Press any Key...";
        cin.ignore();
        cin.get();
        return;
    }
    bool flag = false;//for false condition
    while (inFile.read(reinterpret_cast<char *> (&st), sizeof(student)))
    {
        if (st.getIDNum() == n)
        {
            st.showdata();
            flag = true;
        }
    }
    inFile.close();//closes the file
    if (flag == false)
        cout << "\n\nrecord not exist";//prints record not exist
    cin.ignore();
    cin.get();
}


void modify_student(int n)//to modify the record
{
    bool found = false;//for false condition
    student st;
    fstream File;
    File.open("student.dat", ios::binary | ios::in | ios::out);//opens the file student.dat
    if (!File)
    {
        cout << "File could not be open !! Press any Key...";
        cin.ignore();
        cin.get();
        return;
    }
    while (!File.eof() && found == false)
    {

        File.read(reinterpret_cast<char *> (&st), sizeof(student));//reads the file
        if (st.getIDNum() == n)
        {
            st.showdata();
            cout << "\n\nPlease Enter The New Details of student" << endl;
            st.getdata();
            int pos = (-1)*static_cast<int>(sizeof(st));
            File.seekp(pos, ios::cur);
            File.write(reinterpret_cast<char *> (&st), sizeof(student));
            cout << "\n\n\t Record Updated";
            found = true;
        }
    }
    File.close();//closes the file
    if (found == false)
        cout << "\n\n Record Not Found ";
    cin.ignore();
    cin.get();
}



void delete_student(int n)//to delete the student record
{
    student st;
    ifstream inFile;
    inFile.open("student.dat", ios::binary);//opens the student.dat file
    if (!inFile)
    {
        cout << "File could not be open !! Press any Key...";
        cin.ignore();
        cin.get();
        return;
    }
    ofstream outFile;
    outFile.open("Temp.dat", ios::out);//to open another file
    inFile.seekg(0, ios::beg);
    while (inFile.read(reinterpret_cast<char *> (&st), sizeof(student)))
    {
        if (st.getIDNum() != n)
        {
            outFile.write(reinterpret_cast<char *> (&st), sizeof(student));
        }
    }
    outFile.close();//to open another file
    inFile.close();
    remove("student.dat");
    rename("Temp.dat", "student.dat");
    cout << "\n\n\tRecord Deleted ..";
    cin.ignore();
    cin.get();
}





int main()
{
    char ch;
    int num;
    cout.setf(ios::fixed | ios::showpoint);
    cout << setprecision(2);
    do
    {
        system("cls");
        cout << "\t===================================";
        cout << "\n\n\t1. CREATE STUDENT RECORD";
        cout << "\n\n\t2. DISPLAY ALL STUDENTS RECORDS";
        cout << "\n\n\t3. SEARCH STUDENT RECORD ";
        cout << "\n\n\t4. MODIFY STUDENT RECORD";
        cout << "\n\n\t5. DELETE STUDENT RECORD";
        cout << "\n\n\t6. EXIT";
        cout << "\n\n\t===================================";
        cout << "\n\n\tPlease Enter Your Choice (1-6): ";
        cin >> ch;
        system("cls");
        switch (ch)//uses switch casee
        {
        case '1':   write_student(); break;
        case '2':   display_all(); break;
        case '3':   cout << "\n\n\tPlease Enter Student's ID number: "; cin >> num;
            display_sp(num); break;
        case '4':   cout << "\n\n\tPlease Enter Student's ID number: "; cin >> num;
            modify_student(num); break;
        case '5':   cout << "\n\n\tPlease Enter Student's ID number: "; cin >> num;
            delete_student(num); break;
        case '6':   exit(0);;
        default:    cout << "\a";

        }
    } while (ch != '6');

    return 0;
}
  • if anyone can help me I will be very grateful to you. I just confused that how to sort the records –  Dec 30 '20 at 08:10
  • `if (inFile.seekg(reinterpret_cast (&st)))` is questionable. A) you need to seek to an offset from a position in ta file, not a memory address B) If you are having to seek while writing a file you've already lost. Sort the output container, write the sorted container sequentially. – user4581301 Dec 30 '20 at 08:17
  • 1
    Easiest way to sort: [`std::sort`](https://en.cppreference.com/w/cpp/algorithm/sort) – user4581301 Dec 30 '20 at 08:18
  • can you tell me where I have to make changes??? –  Dec 30 '20 at 08:26
  • edit in code so that I will understand it a better way. Thnaks –  Dec 30 '20 at 09:17

1 Answers1

2

The main difficulty with showing students in sorted order is that your program works by having every function read a file and operate on each student record sequentially. Sorting can only happen when you have all of the data loaded into your program. In order to display a sorted list of students, you need to load all of the student records into your program and put them all in the same container. A std::vector<student> is the simplest container to work with here.

So, I think the overall flow of your program should work like this:

  1. Read the entirety of student.dat and put all student information found there in a container like std::vector<student>.
  2. Sort the container.
  3. Let the user manipulate the records (create, read, update, delete) by modifying the members of the std::vector<student>.
  4. When the user wants to exit, write the contents of the std::vector<student> back to the file students.dat (possibly with an option to quit without saving).

In the next section, suggestions 1 and 2 answer your question while suggestion 3 tells how the rest of your program will need to be changed to work with the first two suggestions.

Some suggestions to do this:

  1. Make it easier to load a student from a file.

Create a method for the student class that takes a std::ifstream& as an argument. That way, after you open a file, you can load all of the student data like this:

int main()
{
    ifstream inFile("student.dat");
    std::vector<student> all_students;
    while(inFile)
    {
        student st;
        st.getData(inFile);
        all_students.push_back(st);
    }

    // continue with program
}

This method will be very similar to the current student::getData() method, but it will skip the text prompts. I also find this way much easier to understand than your reinterpret_cast code that makes me worry about what it actually does. Is student.dat human readable in your current code?

  1. Create a comparison function bool operator<(const student& A, const student& B) for sorting.

This function should return true if the A student should be sorted before B student and false otherwise. Once this method is created, then you can call std::sort(all_students.begin(), all_students.end()) to sort the student list by the criteria defined in that comparison function. The std::sort() function will need to be called after every modification to the student list.

  1. All functions that manipulate student data should get passed the all_students data

It is much easier to work with the student data directly through purpose-written methods rather than doing complicated manipulations of filestream data. For example, if you passed std::vector<student>& to the modify_student() function, it would look like this:

void modify_student(std::vector<student>& all_students, int n)//to modify the record
{
    for (auto& st : all_students)
    {
        if (st.getIDNum() == n)
        {
            st.showdata();
            cout << "\n\nPlease Enter The New Details of student" << endl;
            st.getdata();
            return;
        }
    }
    cout << "\n\n Record Not Found ";
}

If you are not working in C++11 or later, this is equivalent:

void modify_student(std::vector<student>& all_students, int n)//to modify the record
{
    for (size_t i = 0; i < all_students.size(); ++i)
    {
        student& st = all_students[i];
        if (st.getIDNum() == n)
        {
            st.showdata();
            cout << "\n\nPlease Enter The New Details of student" << endl;
            st.getdata();
            return;
        }
    }
    cout << "\n\n Record Not Found ";
}

This is much simpler since you don't have file-traversal and user input/output hiding the actual logic of the function.

If a function is only displaying data like display_all(), then you should pass the student list as const std::vector<student>& all_students.


There's much more to be done to improve this program, but I think these suggestions should get you started thinking in a more organized way.

Mark H
  • 585
  • 3
  • 11
  • my student.dat file is not readable only the char type fields are readable. means student name, the course only while the other two properties mean int properties are not readable. –  Dec 30 '20 at 09:50
  • @FarooqAhmad I thought so. Writing the file that way is a valid choice. It would definitely improve your code if you had a separate dedicated function for reading data from a file and a separate dedicated function for writing data. – Mark H Dec 30 '20 at 10:11
  • void write_student()//to create students record { student st; ofstream outFile; ifstream inFile; outFile.open("student.dat", ios::binary | ios::app);//opens file student.dat st.getdata(); //cout << st.getIDNum(); if (inFile.seekg(reinterpret_cast (&st))) { } outFile.write(reinterpret_cast (&st), sizeof(student));//writes the file outFile.close();//closes the file cout << "\n\nStudent record Has Been Created "; cin.ignore(); cin.get(); } –  Dec 30 '20 at 10:24
  • The above code is for writing the data in student.dat file –  Dec 30 '20 at 10:25
  • void display_all()//to display the student record –  Dec 30 '20 at 10:26
  • These are both separate functions. –  Dec 30 '20 at 10:27
  • @FarooqAhmad I meant that there should be one function to read `student.dat` that returns a `std::vector` with all of the data from the file. There should be another function that takes a `std::vector` and writes all data to `students.dat`. No other function should touch `student.dat`. All other functions should take the `std::vector` as input. – Mark H Dec 30 '20 at 18:42
  • okay, I understand Thanks for helping me. This was really helpful for me. Thanks agian –  Dec 31 '20 at 05:48
  • @FarooqAhmad You're welcome. Good luck with your codidng! – Mark H Dec 31 '20 at 07:30