0

I'm working on this linked list project where I'm supposed to save the employee data in a linked list and apply some operations. and I am new with c++ so I'll show you my code and please help me with it. my questions are:

1- whenever I enter a full name the program keeps going in an infinite loop! i used getline() method and still its not working. but if I enterd just the first name it works fine.

2- I don't know how I can display or find the employee information if I used the methods I create it gives me random data. my code:

main:

#include<iostream>
#include<string>
#include <fstream>
#include "EmployeeList.cpp"
using namespace std;

int main(){
    string name;
    int choice, id;
    double Salary;
    EmployeeList* employee = new EmployeeList();

    cout<<"***********************************************"<<endl;
    cout<<"**********EMPLOYEE MANAGEMENT SYSTEM***********"<<endl;
    cout<<"***********************************************\n\n"<<endl;

    do{
        cout<<" 1--->Press 1 to INSERT EMPLOYMENT:"<<endl;
        cout<<" 2--->Press 2 to FIND EMPLOYMENT INFO ID:"<<endl;
        cout<<" 3--->Press 3 to DELETE EMPLOYMENT ID:"<<endl;
        cout<<" 4--->Press 4 to SEARCH HIGHEST SALARY:"<<endl;
        cout<<" 5--->Press 5 to DISPLAY ALL EMOLYMENTS:"<<endl;
        cout<<" 6--->Press 6 to REVERSE DISPLAY ALL EMPLOYMENTS:"<<endl;
        cout<<" 7--->Press 7 to EXIT:"<<endl;
        cout<<"\n Enter Your Choice: ";
        cin>>choice;

        switch(choice){
            case 1:
                cout<<endl;
                cout<<"Enter name : ";
                getline(cin,name);
                cout<<"Enter ID : ";
                cin>>id;
                cout<<"Enter Salary : ";
                cin>>Salary;
                cout<<endl;
                employee ->INSERTEMPLOYMENT(name,id,Salary);
            break;

            case 2:
                cout<<endl;
                cout<<"Enter ID : ";
                cin>>id;
                cout<<endl;
                employee->FINDEMPLOYMENTINFOID(id);
            break;

            case 3:
                cout<<endl;
                cout<<"Employee ID : ";
                cin>>id;
                cout<<endl;
                employee-> DELETEEMPLOYMENTID(id);
            break;

            case 4:
                cout<<endl;
                employee->SEARCHHIGHESTSALARY();
            break;

            case 5:
                cout<<endl;
                employee->DISPLAYALLEMPLOYMENTS();
            break;

            case 6:
                cout<<endl;
                employee->REVERSEDISPLAYALLEMPLOYMENTS(employee->getHead());
            break;

            case 7:
                exit(0);
            default:
                cout<<"Invalid choice."<<endl;
            break;
        }
    } while (true);


    return 0;
}

Employee:

#include<iostream>
#include<stdlib.h>

using namespace std;

class Employee{
    private:
        string name;
        int ID;
        double Salary;
        Employee* next;

    public:
        //Constructor
        Employee (string n, int id, double s){
            n = name;
            id = ID;
            s = Salary;
            this->next = NULL;
        }

        //Setters
        void setName(string n){
            n = name;
        }
        void setID(int id){
            id = ID;
        }
        void setSalary(double s){
            s = Salary;
        }
        void setNext(Employee* next){
            this->next = next;
        }

        //Getters
        string getName(){
            return name;
        }

        int getID(){
            return ID;
        }

        double getSalary(){
            return Salary;
        }   
        Employee* getNext(){
            return this->next;
        }
};

EmployeeList:

#include "Employee.cpp"
using namespace std;

class EmployeeList{
    private:
        Employee* head;
    public:
    //Constructor
        EmployeeList(){         
            head = NULL;
        }
    //getter
        Employee* getHead(){
            return head;
        }

    //insert method 
        void INSERTEMPLOYMENT (string name, int id, double Salary){
            Employee* newnode = new Employee(name, id, Salary);
            if(head == NULL){
                head = newnode;
            } 
            else {
                Employee* temp = head;
                while(temp->getNext() != NULL){
                    temp = temp->getNext();
                }
                temp->setNext(newnode);
            }

            cout<<"The employee record was added successfully."<<endl;
            cout<<"------------------------------------------"<<endl;
        }

        //info
        void FINDEMPLOYMENTINFOID (int id){
            Employee *temp = head;
            bool status = false;
            while(temp != NULL){
                if(temp->getID() == id){
                    status = true;
                    cout<<"Employee Name = "<<temp->getName()<<endl;
                    cout<<"Employee ID = "<<temp->getID()<<endl;
                    cout<<"Employee Salary = "<<temp->getSalary()<<endl;
                    cout<<"---------------------------------------"<<endl;
                    }
                    temp = temp->getNext();
                }

            if(status == false) {
                cout<<"Employee is not found in the list."<<endl;
                cout<<"--------------------------------------------"<<endl;
                }
            }

        //display
        void DISPLAYALLEMPLOYMENTS (){
            Employee* temp = head;
            while(temp != NULL){
                cout<<"Employee Name = "<<temp->getName()<<endl;
                cout<<"Employee ID = "<<temp->getID()<<endl;
                cout<<"Employee Salary = "<<temp->getSalary()<<endl;
                cout<<"---------------------------------------"<<endl;
                temp = temp->getNext();
                }
            }

};
Nat
  • 37
  • 5
  • 2
    This seems like a great time to learn how to use a *debugger* to step through your code statement by statement while monitoring variables and their values. – Some programmer dude Nov 05 '21 at 08:09
  • 1
    As a possible hint to some of your problems, the `Enter` key you press to give the `choice` input is added to the input buffer as a newline `'\n'`. The input operator `>>` does *not* remove this newline. Instead it will be read by `std::getline` as an "empty" line. – Some programmer dude Nov 05 '21 at 08:13
  • You should read [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction). Mixing `std::getline` and `>>` is tricky. As far as the infinite loop goes you need to be checking if input is successful or not and handling errors appropriately. – Retired Ninja Nov 05 '21 at 08:15
  • Err... `#include "EmployeeList.cpp"` has lighted a big red flag. The file is indeed to be included but the standard convention in C++ language is to name it `EmployeeList.h`. Best practices recommend to have .h for included files and .cpp for files that are directly compiled. The same `Employee.cpp` should be `Employee.h` – Serge Ballesta Nov 05 '21 at 08:17
  • 1
    Still in conventions, CAPITALIZED_WORDS are commonly only used for constants. Using them for methods will unsettle future readers and maintainers (unless you have a different convention in your team, but this one has lighted an orange flag...) – Serge Ballesta Nov 05 '21 at 08:21

1 Answers1

2

There are 2 major problems here.

  1. Assignment are not reversible...

    In Employee class most assignment are reversed. The constructor is:

     //Constructor
     Employee (string n, int id, double s){
         n = name;     // replace the local copy of n with name!!!
         id = ID;
         s = Salary;
         this->next = NULL;
     }
    

    It should of course be:

     //Constructor
     Employee(string n, int id, double s) {
         name = n;
         ID = id;
         Salary= s;
         this->next = NULL;
     }
    

    This is the reason why your Employee instances only contain garbage values...

  2. Mixing getline and stream extractor is dangerous

    When you use a stream extractor to read an integer value, the stream pointer is positioned immediately after the last number, so just before the end of line. If you use getline immediately after that, you will read that newline character only and will get an empty string. A simple trick is to consistently skip over empty lines:

     case 1:
         cout << endl;
         cout << "Enter name : ";
         for (;;) {
             getline(cin, name);
             if (name != "") break;
         }
     ...
    

That should be enough to fix the immediate problems. But others are still around:

  • you never test the state of the input streams: if the users types an incorrect number you will not detect it and your program will have a wrong behaviour

  • EmployeeList being a linked list should behave as a container: it should automatically destroys its elements in its destructor. And because of that and of the rule of 5, it should also have a custom (or deleted) copy constructor and copy assignment operator.

  • constructor have a special syntax to directly initialize their members instead of first default initialize them and then assign to them. Not only it is slightly more efficient, but it is the only way to initialize const members. For that reason the idiomatic way should be:

      //Constructor
      Employee (string n, int id, double s)
              : name(n), ID(id), Salary(s), next(nullptr) {}
    
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • 1
    @Someprogrammerdude: You are right. I have added it in the *improvement list*. But I would prefere to avoid the discussion between initialization and assignment here... – Serge Ballesta Nov 05 '21 at 09:34