C++: Help with pointer array

Discussion in 'Web Design & Coding' started by Luna, Apr 22, 2007.

  1. Luna

    Luna OSNN Senior Addict Folding Team

    Messages:
    303
    Location:
    Houston, Tx
    This is an assignment I've been working on that really has me stuck. Long story short, our professor has given us a application that is supposed to allow a user to Add, Remove, and Modify employees into an array. Most of the code is actually done for us (can't change it), but we need to complete the sections that write and read information from an array. Simple enough... except this array is a pointer?

    There are two classes in this application. In the class 'Company', you can see we have a private entry for an array called employees where the information will be stored.
    Code:
    /////////////////////////////////////////////////////////////////////
    //    Define the class Employee with public attributes
    //    This class describes essentials of the employee.
    class Employee
    {
    public:
        int        id;                //    Employee ID
        double    maxPayRate;        //    Maximum pay rate
        int        maxHoursToWork;    //    Maximum hours that they can work
    
    };
    
    /////////////////////////////////////////////////////////////////////
    //    This is the class Company. It contains data and methods for 
    //    up to 10 employees. 
    class Company
    {
    public:
        //    Default constructor
        Company() {nextIndex=0;};
    
        //    These are class methods to add, modify, delete and 
        //    display the employees. 
        void AddEmployee();
        void ModifyEmpoyee();
        void DeleteEmployee();
        void DisplayEmployees();
    
    private:
        //    These is private class data
        //    This pointer array holds the data for all of the employees
        Employee*  employees[10];
    
        //    This is the next index that will be used in the 
        //    employees array above. 
        int        nextIndex;
    };
    So since most of this is done for us, I jump down to the void Company::AddEmployee() function. At first I thought the following code would allow me to store information into this array:
    Code:
    cin >> employees[0]->id;
    When this line is reached however, it crashes. When I debug, it looks like there is no memory allocated for this array, or it's not defined yet. Am I missing something simple?

    Without the use of pointers I have no problem storing the information directly into the variables defined in the Employee class (or even into an array that's not defined as *), as seen below. I just don't know how to get it into the array that was defined in the above Class. I'm sure there is a way to input it directly into the array.
    Code:
    void Company::AddEmployee()
    {
        Employee emp = {0, 0.0, 0};
        cout << "Please Enter the Employees Information: ";
        cout << "\n \nID: ";
        cin >> emp.id;
    
        so on... so forth...
    }
     

    Attached Files:

    Last edited: Apr 22, 2007
  2. LordOfLA

    LordOfLA Godlike!

    Messages:
    7,027
    Location:
    Maidenhead, Berkshire, UK
    shouldn't that be cin >> *employees[0]->id; ?

    My C++ isn't great and my C is based on DOS work I didn back in 98/99 but that should point you in the right direction.

    I believe you may also be able to reference it with the ampersand symbol prefixed too (&).
     
  3. LeeJend

    LeeJend Moderator

    Messages:
    5,291
    Location:
    Fort Worth, TX
    " Simple enough... except this array is a pointer? "

    Don't confuse pointers and memory.

    A pointer is the address of the memory, not the contents of that memory.

    You must create the memory object and then create a pointer to that memory.

    Once you create the memory and have it's location you can pass the small pointer (a few bytes in size) between sub programs instead of passing massive blocks of data. Pointers are used to save memory and increase execution speed.

    C++ has different syntax than C for when you access memory as opposed to using a pointer to refer to that memory. Also if the memory object is private then the Class must provide the methods to actually work on the memory object. This is an example of how to work within the C++ capability of compartmentalizing data/functions to prevent somebody from stomping all over data they shouldn't. C on the other hand will allow wanton destruction of data (and code).

    So the process is:
    1) Create the memory object
    2) Create a pointer to it
    3) Use the correct syntax to refer to the memory object as created in steps 1 & 2.

    The code is left as a learning exercise...
     
    Last edited: Apr 22, 2007
  4. albybum

    albybum Penguin Rancher

    Messages:
    280
    Location:
    Elizabethton, TN
    You should probably declare and define your employees array this way.

    Declare your pointer:
    Employee* employees;

    Allocate memory and store pointer value:
    In your Company constructor you should have
    employees=new Employee[10];


    Then you should be able to access your data by the following syntax
    Company::employees[nextIndex].id

    The index or "[]" bracket notation does the dereferencing for you, no need for the -> symbol.

    Also, I'm not quite sure why you were trying to explicitly call Main() inside your addEmployee function. The function will return to main when it has completed.

    I removed that from my attached file and also moved main to the end of the document. You should keep all your class material together.

    Make sure you understand the differences between your original code and the code attached.

     

    Attached Files:

    Last edited: Apr 22, 2007
  5. Luna

    Luna OSNN Senior Addict Folding Team

    Messages:
    303
    Location:
    Houston, Tx
    Thanks for the help! :)

    I called Main inside that function so I will be returned to the prompt once the employee was added. I guess there are other ways to do that, but right now I was focused on getting information into the array.

    I will give all of this a try and see how it works out. :up:
    I had a basic idea of how pointers worked on a very simple level, but then when we throw in an array, class, and public/private data I got a bit overwhelmed. Hopefully the more I do this the more it will make sense.
     
    Last edited: Apr 22, 2007
  6. LeeJend

    LeeJend Moderator

    Messages:
    5,291
    Location:
    Fort Worth, TX
    The type of data (char, array, structure, object) being passed is not really important in understanding pointer usage.
    1) Get the starting address (the pointer to the data) and
    2) then index into the array, structure, object, string, whatever.

    No Class (Original C)
    * (pointer to data start) and & (address of data) are the pointer operators.

    With Class (C++ extensions)
    -> (pointer) and :: are the pointer operators.

    also the . (reference) operator which was added for specific functionality allows you to use an alternate syntac (i.e the & is not required in your code)

    Unfortunately pointer rules change from C to C++ because of C++ Encapsulation (hides away the code and functions).

    The compiler is smart enough to establish the correct offsets for your data type. C++ complicates all the rules which is why it is really painful going from C to C++ code.

    When in pain google "going from C to C++ (your question)" it will improve getting hits to explain the difference.

    PS I've used over 8 different languages over the years and I hate C++. The rest had strengths and values for different applications and I actually liked them ( I barely tolerate Basic).
     
  7. Luna

    Luna OSNN Senior Addict Folding Team

    Messages:
    303
    Location:
    Houston, Tx
    Thanks for the information. It's starting to make sense to me. I've never used code like this before so it's definitely a learning process.

    albybum, you got me on the right track there with: employees=new Employee[10]. I was actually able to complete the rest of the program using that bit of code. If I understand correctly, I have to construct data for this array before I can start using it. By default it's just an array of pointers that point to nothing. The only downside is it fell out of the scope of the application and I still need to find a way to keep the array defined as:
    Code:
     private:
        //    These is private class data
        //    This pointer array holds the data for all of the employees
        Employee* employees[10];

    My professor did throw me a hint as to how it can be done. It makes sense for the snippet of code he sent me, since the following code is all done in the main() function. For the program I am writing it does not seem to carry over very well since I am constantly moving throughout different functions. I can't set "
    employees[10] = " to much as far as i can tell. If I could, where would I construct the data it will be set = to? I can't seem to do this in the class, and I'm not sure if it's a good idea to do it in the main function.

    His example, not related to the program I am am writing:
    Date* pDate = new Date();
    datePointers = pDate;
    datePointers->showDate();

    Though that example I can access the array with the -> syntax.

    As pure concept, this makes sense to me. In this example, we define an array of pointers called datePointers[5]. A new data type from a Date class is then defined? The array is set equal to this data type. From there we can use the following syntax to store information into this array datePointers->variableName;

    I feel like I'm missing something really simple here, just changing 1 line will be the difference between a good build and a bad one. I'm going to sit down with him on Monday and see if he can clear things up for me. If anyone happens to know off the top of their head what I am doing wrong though, it would be a big help.
     
  8. X-Istence

    X-Istence * Political User

    Messages:
    6,498
    Location:
    USA
    Nope, :: has absolutely nothing to do with pointers. It is used to resolve the scope.

    So for example:

    cout is in the namespace std, to be able to input stuff to cout I need the << operator.

    cout << "Hello";

    would fail since cout is not in the current scope

    std::cout << "Hello";

    Would not fail, since the compiler would know to look in the std namespace.
     
  9. X-Istence

    X-Istence * Political User

    Messages:
    6,498
    Location:
    USA
    Code:
    Please choose a number from the following menu:
    1. Add an Employee
    2. Modify Employee Data
    3. Delete an Employee
    4. Exit
    
    1
    Please Enter the Employees Information: 
     ID: 55
     Pay Rate: 45
     Maximum Work Hours: 10
    
    You have the following 1 employee(s):
    
    Employee ID: 55
    Maximum Hours to Work: 10
    Maximum Pay Rate: 45
    
    
    
    Please choose a number from the following menu:
    1. Add an Employee
    2. Modify Employee Data
    3. Delete an Employee
    4. Exit
    
    1
    Please Enter the Employees Information: 
     ID: 50
     Pay Rate: 20
     Maximum Work Hours: 10
    
    You have the following 2 employee(s):
    
    Employee ID: 55
    Maximum Hours to Work: 10
    Maximum Pay Rate: 45
    
    Employee ID: 50
    Maximum Hours to Work: 10
    Maximum Pay Rate: 20
    
    
    
    Please choose a number from the following menu:
    1. Add an Employee
    2. Modify Employee Data
    3. Delete an Employee
    4. Exit
    
    1
    Please Enter the Employees Information: 
     ID: 10
     Pay Rate: 10
     Maximum Work Hours: 10
    
    You have the following 3 employee(s):
    
    Employee ID: 55
    Maximum Hours to Work: 10
    Maximum Pay Rate: 45
    
    Employee ID: 50
    Maximum Hours to Work: 10
    Maximum Pay Rate: 20
    
    Employee ID: 10
    Maximum Hours to Work: 10
    Maximum Pay Rate: 10
    
    
    
    Please choose a number from the following menu:
    1. Add an Employee
    2. Modify Employee Data
    3. Delete an Employee
    4. Exit
    
    3
    
    You have the following 3 employee(s):
    
    Employee ID: 55
    Maximum Hours to Work: 10
    Maximum Pay Rate: 45
    
    Employee ID: 50
    Maximum Hours to Work: 10
    Maximum Pay Rate: 20
    
    Employee ID: 10
    Maximum Hours to Work: 10
    Maximum Pay Rate: 10
    
    ID of employee to remove: 50
    
    You have the following 2 employee(s):
    
    Employee ID: 55
    Maximum Hours to Work: 10
    Maximum Pay Rate: 45
    
    Employee ID: 10
    Maximum Hours to Work: 10
    Maximum Pay Rate: 10
    
    
    
    Please choose a number from the following menu:
    1. Add an Employee
    2. Modify Employee Data
    3. Delete an Employee
    4. Exit
    
    1
    Please Enter the Employees Information: 
     ID: 24
     Pay Rate: 24
     Maximum Work Hours: 2
    
    You have the following 3 employee(s):
    
    Employee ID: 55
    Maximum Hours to Work: 10
    Maximum Pay Rate: 45
    
    Employee ID: 24
    Maximum Hours to Work: 2
    Maximum Pay Rate: 24
    
    Employee ID: 10
    Maximum Hours to Work: 10
    Maximum Pay Rate: 10
    
    
    
    Please choose a number from the following menu:
    1. Add an Employee
    2. Modify Employee Data
    3. Delete an Employee
    4. Exit
    
    4
    
    You have the following 3 employee(s):
    
    Employee ID: 55
    Maximum Hours to Work: 10
    Maximum Pay Rate: 45
    
    Employee ID: 24
    Maximum Hours to Work: 2
    Maximum Pay Rate: 24
    
    Employee ID: 10
    Maximum Hours to Work: 10
    Maximum Pay Rate: 10
    This is what you need right?
     
  10. X-Istence

    X-Istence * Political User

    Messages:
    6,498
    Location:
    USA
    Code:
    // Assignment 
    // 04-18-2007
    // Matthew Lytwyn - mslytwyn
    // Program that utilizes more advanced and abstract coding / logic
    // Users can Enter, Modify, and Delete employees
    
    #include <iostream>
    
    /////////////////////////////////////////////////////////////////////
    //      Define the class Employee with public attributes
    //      This class describes essentials of the employee.
    
    class Employee {
            public:
                    int id;                         //      Employee ID
                    double maxPayRate;              //      Maximum pay rate
                    int     maxHoursToWork; //      Maximum hours that they can work
    };
    
    
    
    /////////////////////////////////////////////////////////////////////
    //      This is the class Company. It contains data and methods for 
    //      up to 10 employees. 
    
    class Company {
            public:
                    //      Default constructor
                    Company() : nextIndex(0) {
                            
                            // Let's make sure we are not pointing at random data in memory, but are null instead 
                            for (int i = 0; i < 10; ++i) employees[i] = 0;   
                    };
                    //      These are class methods to add, modify, delete and 
                    //      display the employees. 
                    void AddEmployee();
                    void ModifyEmpoyee();
                    void DeleteEmployee();
                    void DisplayEmployees();
            private:
                    //      These is private class data
                    //      This pointer array holds the data for all of the employees
                    Employee*  employees[10];
                    //      This is the next index that will be used in the 
                    //      employees array above. 
                    int nextIndex;
                    
                    bool isFull() {
                            for (int i = 0; i < 10; ++i) {
                                    if (employees[i] == 0) {
                                            return false;
                                    }
                            }
                            
                            return true;
                    };
    };
    
    /////////////////////////////////////////////////////////////////////
    //      Definition of the AddEmployee() method of the Company class
    //      This method will add an employee to the Company class instance. 
    //      The attributes of the employee should be those of the user's 
    //      own choosing.
    
    void Company::AddEmployee() {
            //      Check whether there are already 10 employees or not and
            //      return if there are. 
            if (isFull()) {
                    std::cout << "Sorry, the employee list is full!" << std::endl;
                    return;
            }
            
            //      Ask the user for the 3 attributes of the new employee
            //      and assign those attributes to the new employee. 
            Employee* emp = new Employee();
            std::cout << "Please Enter the Employees Information: " << std::endl;
            std::cout << " ID: ";
            std::cin >> emp->id;
            std::cout << " Pay Rate: ";
            std::cin >> emp->maxPayRate;
            std::cout << " Maximum Work Hours: ";
            std::cin >> emp->maxHoursToWork;
            
            // We add the employee to the array
            for (int i = 0; i < 10; ++i) {
                    if (employees[i] == 0) {
                            employees[i] = emp;
                            nextIndex++;
                            break;
                    }
            }
            
            return;
    }
    
    
    
    /////////////////////////////////////////////////////////////////////
    //      Definition of the ModifyEmpoyee() method of the Company class
    //      This method will modify an attribute of the employee in 
    //      the Company class instance. The employee and attribute should be
    //      ones of the user's own choosing.
    void Company::ModifyEmpoyee() {
            //      Show all of the current employees
            //      Ask the user the ID of which employee that they wish to
            //      modify. 
    
            this->DisplayEmployees();
    
            int empId;
            
            std::cout << "ID of employee to modify: ";
            std::cin  >> empId;
            
            // This is where we are going to temporarily hold a pointer to the employee
            Employee* emp = 0;
            
            // Search for the employee with the right ID, since it is not the same as what index they are in the array
            for (int i = 0; i < 10; ++i) {
                    if (employees[i] == 0)
                            continue;
                    if (employees[i]->id == empId)
                            emp = employees[i];
            }
            
            // Check if there is such an employee with such an ID
            if (emp == 0) {
                    std::cout << "Invalid employee ID!" << std::endl;
                    return;
            }
            
            //      Ask the user which attribute of the employee that they
            //      want to modify and then modify it appropriately.
            
            int choice = 0;
            do {
                    std::cout << std::endl << std::endl;
                    std::cout << "Please choose a number from the following menu:" << std::endl;
                    std::cout << "1. Change ID" << std::endl;
                    std::cout << "2. Change Payrate" << std::endl;
                    std::cout << "3. Change Max Hours" << std::endl;
                    std::cout << "4. Save Employee and back to main" << std::endl;
                    std::cout << std::endl;
    
                    std::cin >> choice;
                    if (choice == 1) {
                            std::cout << " ID: ";
                            std::cin >> emp->id;
                    }
                    else if (choice == 2) {
                            std::cout << " Pay Rate: ";
                            std::cin >> emp->maxPayRate;
                    }
                    else if (choice == 3) {
                            std::cout << " Maximum Work Hours: ";
                            std::cin >> emp->maxHoursToWork;
                    }
            } while (choice != 4);
             
            return;
    }
    
    /////////////////////////////////////////////////////////////////////
    //      Definition of the DeleteEmployee() method of the Company class.
    //      This method will delete the employee of the user's choosing from
    //      the Company class instance. 
    
    void Company::DeleteEmployee() {
            //      Show all of the current employees
    
            this->DisplayEmployees();
    
            //      Ask the user the ID of which employee that they wish to
            //      delete.
            
            int empId;
            std::cout << "ID of employee to remove: ";
            std::cin  >> empId;
            
            Employee* emp = 0;
            
            for (int i = 0; i < 10; ++i) {
                    if (employees[i] == 0)
                            continue;
                    if (employees[i]->id == empId) {
                            emp = employees[i];
                            // Set the pointer in the array back to NULL. Causing it to not be shown in DisplayEmployees
                            employees[i] = 0;
                    }
            }
            
            if (emp == 0) {
                    std::cout << "Invalid employee ID!" << std::endl;
                    return;
            }
    
            //      Delete the chosen employee from the array of employees
            //      as represented in this class. 
    
            // Actually remove the entry from memory so as to not leak objects
            nextIndex--;
            delete emp;
    
    }
    
    
    
    /////////////////////////////////////////////////////////////////////
    //      Definition of the DisplayEmployees() method of the Company class.
    //      This will display all of the employees currently in the company 
    //      to an output console using std::cout.
    
    void Company::DisplayEmployees() {
            if (nextIndex == 0) {
                    std::cout << std::endl << "You do not have any employees yet." << std::endl;
                    return;
            }
            // We have employees :D
            std::cout << std::endl << "You have the following " << nextIndex << " employee(s):" << std::endl;
            for (int i = 0; i < 10; ++i) {
                    if (employees[i] != 0) {
                            std::cout << std::endl;
                            std::cout << "Employee ID: " << employees[i]->id << std::endl;
                            std::cout << "Maximum Hours to Work: " << employees[i]->maxHoursToWork << std::endl;
                            std::cout << "Maximum Pay Rate: " << employees[i]->maxPayRate << std::endl;
                    }
            }
    
            std::cout << std::endl;
    }
    
    /////////////////////////////////////////////////////////////////////
    //      The program begins with this main() function. 
    
    int main() {
    
            Company* myCompany = new Company();
            int choice = 0;
            do {
                    std::cout << std::endl << std::endl;
                    std::cout << "Please choose a number from the following menu:" << std::endl;
                    std::cout << "1. Add an Employee" << std::endl;
                    std::cout << "2. Modify Employee Data" << std::endl;
                    std::cout << "3. Delete an Employee" << std::endl;
                    std::cout << "4. Exit" << std::endl;
                    std::cout << std::endl;
    
                    std::cin >> choice;
                    if (choice == 1) {
                            myCompany->AddEmployee();
                    }
                    else if (choice == 2) {
                            myCompany->ModifyEmpoyee();
                    }
                    else if (choice == 3) {
                            myCompany->DeleteEmployee();
                    }
    
                    myCompany->DisplayEmployees();
            } while (choice != 4);
    }
    Here it is, all done :D. I stopped using the nextIndex stuff since it would only complicate things if you removed an employee from the middle of the stack as it would mean shifting all the other entries one up, while possible, just not worth it.
     

    Attached Files:

  11. X-Istence

    X-Istence * Political User

    Messages:
    6,498
    Location:
    USA
    Some notes:

    Code:
    Employee* employees[10]
    Means it is an array of pointers. In the code I attached I loop through and set each and every one of them to 0, which means it will be easier to detect that it is a valid or invalid entry in the array list.

    Then in the add Employees, I create another pointer:

    Employee* emp = new Employee();

    Since it is a pointer as well, I then find an empty spot in the array using another loop (that is why I set them all to 0), and assign it. Now, I return and the program goes on.

    Read the source code, if you have any questions, please ask me!
     
  12. Luna

    Luna OSNN Senior Addict Folding Team

    Messages:
    303
    Location:
    Houston, Tx
    Thanks for all of your work. I actually have about 90% of theprogram done already :dead: :speechless:, except for one small section. I get thrown off when it comes to using the array of pointers and constructing data for them. I still need to be able to use the following syntax to access it: employees->variableName;

    As a rule I can't change any of the code that's already in the program, I can just add code to the Add / Modify / Delete sections, or into the class sections. I see you filled the array by using for (int i = 0; i < 10; ++i) employees = 0; I could not seem to incorporate that into my program though, maybe due to the changes made to that class.

    In short, I have the following code which I should not change, but can add to.
    Code:
    class Employee
    {
    public:
        int        id;                //    Employee ID
        double    maxPayRate;        //    Maximum pay rate
        int        maxHoursToWork;    //    Maximum hours that they can work
    
    };
    
    class Company
    {
    public:
        Company() {nextIndex=0;};
    
        void AddEmployee();
        void ModifyEmpoyee();
        void DeleteEmployee();
        void DisplayEmployees();
    
    private:
    
        Employee* employees[10];
    
        int        nextIndex;
    };
    I then jump down to the Add / Modify / Delete functions and want to dump data into this array. Currently, the array is full of pointers that all point to an invalid memory location.

    So what I get stuck on is how I can use code like employees[nextIndex]->id; without changing the above code. albybum got me really close by using a constructor, employees=new Employee[10];. This required that I change the way I define the array however, and also meant I would use this notation employees[nextIndex].id compared to employees[nextIndex]->id.

    I guess in short I'm looking for a constructor that allows me to populate this array with valid memory locations for all the pointers, but does not change the above code. I will try to get my professor to give me some hints tomorrow.
     
    Last edited: Apr 23, 2007
  13. X-Istence

    X-Istence * Political User

    Messages:
    6,498
    Location:
    USA
    You should be able to incorporate that in your class, just put it in the constructor after you set nextIndex to 0.

    In your add function you need to create a new Employee* and then create a new employee like I did in my code. You then assign that Employee* to one of the array indices like so:

    Employee* emp = new Employee();
    employees = emp;

    Then you can access it using:

    employees->id;

    Where i can be a number, or can be replaced by another variable.

    The way the program is set up though, if you delete an employee from the middle of the array, you have to shift all the entries in the array, otherwise your nextIndex will be off, and it will fail.

    Also, I made no real changes to the class in any way shape or form, unless adding another function is not allowed. That function can be removed, and it's logic may instead be added to the Add function where the call is currently made.
     
  14. Luna

    Luna OSNN Senior Addict Folding Team

    Messages:
    303
    Location:
    Houston, Tx
    The Delete part was something I was going to ask my Prof. about since I also see it as a potential for problems.

    I see what you mean about:

    Employee* emp = new Employee();
    employees = emp;

    I did mine as follows:
    EDIT:

    Actually, I figured it out I believe. I just had to increment emp every time it assigned a memory location to a pointer in the array. If I don't, every pointer will point to the same location.

    At first this caused a problem because it ran every time I called this function, but if I tell this only to run while nextIndex is 0, then it only runs once.

    Code:
    if (nextIndex == 0)
        {
            Employee* emp = new Employee();
            for (int i=0; i<10; i++)
                employees[i] = emp++;
        }
    Since I know the Add Employee function will always run first, I am safe in placing this code here. It seems risky to do this however if you are unsure which function will run first. I guess then, you would do this in the class itself, or in the main function?
     
    Last edited: Apr 23, 2007
  15. X-Istence

    X-Istence * Political User

    Messages:
    6,498
    Location:
    USA
    emp SHOULD NEVER be incremented. You are doing something very wrong. Read over my code and figure out how I am doing it.
     
  16. Luna

    Luna OSNN Senior Addict Folding Team

    Messages:
    303
    Location:
    Houston, Tx
    It was so simple, I'm not sure why I did not pick it up earlier.

    Employee* emp = new Employee();
    employees[nextIndex] = emp;

    Since nextIndex is incremented by one every time, it will give it a new memory address every time you call it.