1

I keep running into an issue with a program for one of my classes. I'm definitely new to C++ and am hoping someone sees something obvious that I'm just missing. Every time I run it, it successfully compiles but then hits me with three EXC_BAD_ACCESS (code=EXC_I386_GPFLT) errors - one during my definition of the member function Employee::getID(), again in my search() function, and last when I call the search() function in main (all of which have the getID() function inside them. I'm wondering if this is part of a greater problem relating to use of pointers. Any advice would be greatly appreciated - thanks!

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


const int   MAX_NUMBER_OF_EMPLOYEES {100},    // constant number of employees
            DEPENDANT_INSURANCE {20};     // constant insurance cost per dependant;
const float TAX_RATE {0.15};            // constant tax rate

// declaration for Employee class
class Employee
{
  private:
    int id;             // employee ID
    char name[21];      // employee name
    double hourlyPay;   // pay per hour
    int numDeps;        // number of dependents
    int type;           // employee type

  public:
    Employee( int initId=0, char initName[]=0,
              double initHourlyPay=0.0,
              int initNumDeps=0, int initType=0 );  // Constructor

    bool set(int newId, char newName[], double newHourlyPay,
             int newNumDeps, int newType);          // set function that performs input validation
    int getID();            // gets employee ID
    string getName();       // gets employee name
    double getHourlyPay();  // gets employee hourly pay
    int getNumDeps();       // gets employee's number of dependents
    int getType();          // gets employee's type (union/management)
    friend void setEmployees( ifstream&, Employee*[], int&);
};

// declaration for TimecardInfo struct that holds variables for employee
// hours worked, gross pay, tax, insurance, and net pay.
struct TimesheetInfo
{
    float hoursWorked,  // hours worked
          grossPay,     // gross pay
          tax,          // tax taken out
          insurance,    // insurance for dependents taken out
          netPay;       // net pay
    int transID;        // temporary ID to match getID() search
};

void setEmployees( ifstream&, Employee*[], int&);
void setTimesheet( ifstream&, TimesheetInfo*[], int&);
int search( int, Employee*[], int);
void bubbleSort (TimesheetInfo*[], int size);

// begin main function
int main()
{

    float   totalGrossPay {0.0},        // float variable for gross pay for all employees
            totalNetPay {0.0};          // float variable for net pay for all employees
    int     totalTransactions {0},      // int to hold total number of correctly processed transactions
            i = 0,                      // index for loop
            searchIndex,
            tempSearch,
            numEmployees = 0,
            numTrans = 0;
    string  inputFileName,
            outputFileName;
//    Employee *employee;
//    TimesheetInfo *timesheet = nullptr;

    Employee *employee [MAX_NUMBER_OF_EMPLOYEES];      // declare an array of pointers to Employee objects
    TimesheetInfo *timesheet [MAX_NUMBER_OF_EMPLOYEES]; // declare an array of pointer to TimesheetInfo structures

    ifstream inputFile;                 // create a filestream object

    cout << "Enter the name of the employee master data file: ";
    getline(cin, inputFileName);
    //inputFile.open(inputFileName);      // open file into inputFile
    inputFile.open("/Users/davidfralin/Documents/Programming/ACCProgramming/ACC/Xcode Projects/Assignment10/Assignment10/master10.txt");

    while (!inputFile)
    {
        cout << "Error opening file: please enter a valid file name: ";
        getline(cin, inputFileName);
        inputFile.open(inputFileName);
    }

    setEmployees(inputFile, employee, numEmployees);

    // close input file
    inputFile.close();

    // create and open second input file
    ifstream inputFile2;
    cout << "Enter the name of the employee transaction data file: ";
    getline(cin, inputFileName);
    //inputFile2.open(inputFileName);
    inputFile2.open("/Users/davidfralin/Documents/Programming/ACCProgramming/ACC/Xcode Projects/Assignment10/Assignment10/trans10.txt");
    while (!inputFile2)
    {
        cout << "Error opening file: please enter a valid file name: ";
        getline(cin, inputFileName);
        inputFile2.open(inputFileName);
    }

    // create and open output file
    ofstream outputFile;
    cout << "Enter a name for the payroll report file: ";
    getline(cin, outputFileName);
    cout << outputFileName;
    //outputFile.open(outputFileName);
    outputFile.open("/Users/davidfralin/Documents/Programming/ACCProgramming/ACC/Xcode Projects/Assignment10/Assignment10/payroll_report_3.0.txt");

    // Print formatted header for payroll report into output file
    outputFile  << fixed << showpoint << setprecision(2)
                << "****************************************************************\n"
                << "****************** ARMADILLO AUTOMOTIVE GROUP ******************\n"
                << "******************     PAYROLL REPORT 3.0     ******************\n"
                << "****************************************************************\n\n"
                << setw(3) << "ID" << " " << left
                << setw(20) << "Name" << right
                << setw(10) << "Gross Pay"
                << setw(10) << "Tax"
                << setw(10) << "Insurance"
                << setw(10) << "Net Pay" << endl
                << "****************************************************************" << endl;






    // begin loop that iterates as many times as there are employees,
    // which receives the employee's hours worked from inputFile2, perfoms
    // needed calculations, and prints formatted results to output file

    //inputFile2 >> timesheet[i].transID >> timesheet[i].hoursWorked;
    setTimesheet(inputFile2, timesheet, numTrans);

    bubbleSort(timesheet, numTrans);

    cout  << fixed << showpoint << setprecision(2) << endl
    << "****************************************************************\n"
    << "****************** ARMADILLO AUTOMOTIVE GROUP ******************\n"
    << "****************     ERROR & CONTROL REPORT     ****************\n"
    << "****************************************************************\n\n";


    for (i=0; i < numTrans; i++)
    {
        tempSearch = timesheet[i]->transID;
        searchIndex = search(tempSearch, employee, numTrans);
        if (searchIndex == -1)
        {
            cout << "Error: no matching employee data for Employee #:" << timesheet[i]->transID << endl << "\t*Employee info will not appear in payroll report*\n\n";
        }
        for (int j=0; j < numEmployees; j++)
        {
            if (timesheet[i]->transID == employee[j]->getID())
                {
                // input validation for employee ID - if invalid, print error message and do not store
                // employee's info in output file.
                if (!employee[j]->getID())
                {
                    cout << "Error: invalid Employee ID for Employee Transaction: " << i+1 << endl
                    << "\t*Employee info will not appear in payroll report*\n\n";
                }
                // input validation for employee's hours worked - if invalid, print error message and
                // do not store employee's info in output file.
                else if (timesheet[i]->hoursWorked < 0)
                {
                    cout << "Error: invalid hours worked for Employee #:" << timesheet[i]->transID << endl
                    << "\t*Employee info will not appear in payroll report*\n\n";
                }

                // with valid input verified, check for overtime and perfom needed calculations
                else
                {
                // if employee is a union worker and worked overtime, calculate gross pay w/ overtime
                // and store in struct relative to this iteration
                    if (timesheet[i]->hoursWorked > 40 && employee[j]->getType() == 0)
                    {
                        timesheet[i]->grossPay = (40 * employee[j]->getHourlyPay()) + (timesheet[i]->hoursWorked - 40) * employee[j]->getHourlyPay() * 1.5;
                    }
                    // if employee is management or union and didn't work overtime, calculate gross pay
                    // and store in struct relative to this iteration
                    else
                    {
                        timesheet[i]->grossPay = employee[j]->getHourlyPay() * timesheet[i]->hoursWorked;
                    }
            // calculate and store tax, insurance, and net pay for this iteration
                    timesheet[i]->tax = timesheet[i]->grossPay * TAX_RATE;
                    timesheet[i]->insurance = employee[j]->getNumDeps() * DEPENDANT_INSURANCE;
                    timesheet[i]->netPay = timesheet[i]->grossPay - timesheet[i]->tax - timesheet[i]->insurance;

                    outputFile  << right << setw(3) << employee[j]->getID() << " "
                    << setw(20) << employee[j]->getName()
                    << setw(10) << timesheet[i]->grossPay << setw(10) << timesheet[i]->tax << setw(10)
                    << timesheet[i]->insurance << setw(10) << timesheet[i]->netPay << endl;

            // add to running total correctly processed transactions, total gross pay, and total net pay
                    totalTransactions++;
                    totalGrossPay += timesheet[i]->grossPay;
                    totalNetPay += timesheet[i]->netPay;
                }
            }
        }
    }



    // close input file
    inputFile2.close();

    // output to file formatted results for total gross/net pay
    outputFile  << endl << right << setw(24) << "Total Gross Pay: "
                << setw(10) << totalGrossPay << " "
                << setw(19) << "Total Net Pay: "
                << setw(10) << totalNetPay << endl
                << "****************************************************************" << endl;

    // close output file
    outputFile.close();

    // output to file total number of transactions processed w/o error
    cout << "Total transaction correctly processed: " << totalTransactions << endl << endl;

    delete [] *employee;
    delete [] *timesheet;

    return 0;
}

//********************************************************
//                  Employee constructor                 *
// Employee class contructor that sets the object's data *
// members. If the input validation from function "set"  *
// returns "false", initializes all name to a blank      *
// string and all other values to 0.                     *
//********************************************************
Employee::Employee( int initId, char initName[],
                    double initHourlyPay,
                    int initNumDeps, int initType )
{
  bool status = set( initId, initName, initHourlyPay,
                     initNumDeps, initType );

  if ( !status )
  {
    id = 0;
    strcpy(name, "");
    hourlyPay = 0.0;
    numDeps = 0;
    type = 0;
  }
}


//********************************************************
//                  Employee::set                        *
// Employee class member function that that performs     *
// input validation on passed parameters, and if valid,  *
// sets their values and returns "true."
//********************************************************
bool Employee::set( int newId, char newName[], double newHourlyPay,
                                 int newNumDeps, int newType )
{
  bool status = false;

  if ( newId > 0 && newHourlyPay > 0 && newNumDeps >= 0 &&
       newType >= 0 && newType <= 1 )
  {
    status = true;
    id = newId;
    strcpy(name, newName);
    hourlyPay = newHourlyPay;
    numDeps = newNumDeps;
    type = newType;
  }
  return status;
}

//********************************************************
//                  Employee::getID                      *
// Employee class member function that returns the ID of *
// the class object.                                     *
//********************************************************
int Employee::getID()
{
    return id;
}

//********************************************************
//                  Employee::getName                    *
// Employee class member function that returns the name  *
// of the class object.                                  *
//********************************************************
string Employee::getName()
{
    return name;
}

//********************************************************
//              Employee::getHourlyPay                   *
// Employee class member function that returns the       *
// hourly pay of the class object.                       *
//********************************************************
double Employee::getHourlyPay()
{
    return hourlyPay;
}

//********************************************************
//                Employee::getNumDeps                   *
// Employee class member function that returns the       *
// number of dependents of the class object.             *
//********************************************************
int Employee::getNumDeps()
{
    return numDeps;
}

//********************************************************
//                 Employee::getType                     *
// Employee class member function that returns the type  *
// of the class object (union or management).            *
//********************************************************
int Employee::getType()
{
    return type;
}

void bubbleSort (TimesheetInfo* array[], int size)
{
    bool madeAswap = true;    // This allows the for loop to begin iterating
    for (int maxElement = (size - 1); maxElement > 0 && madeAswap; maxElement--)
    {
        for (int index = 0; index < maxElement; index++)
        {
            if (array[index]->transID > array[index + 1]->transID)
            {
                swap (array[index], array[index + 1]);
                madeAswap = true;
            }
        }
    }
}
//************************************************************** //* FUNCTION search
//*
//* Find the location of an item in a list.
//*
//**************************************************************
int search( int srchVal,     // in - value to search for
              Employee *list[],  // in - list to search
              int length)      // in - number of items in list
{
// search list for item and return its position if found
   int index = 0;
   while (index < length)
   {
      if (srchVal == list[index]->getID())
          return index;
      index++;
   }

// item not found - return a flag
   return -1;
}

//**************************************************************
//* FUNCTION getItems
//*
//* Copies item information from file into arrays
//**************************************************************
void setEmployees( ifstream &employeeFile, Employee *employeePtr[], int &numEmployees)
{
    int oneID;             // employee ID
    char oneName[21];      // employee name
    double oneHourlyPay;   // pay per hour
    int oneNumDeps;        // number of dependents
    int oneType;           // employee type

    numEmployees = 0;
    employeeFile >> oneID;
    employeeFile.get( oneName, 21, '\n' );
    employeeFile >> oneHourlyPay >> oneNumDeps >> oneType;

    while (employeeFile && numEmployees < MAX_NUMBER_OF_EMPLOYEES)
    {
        // move new item into arrays and increment item count
        employeePtr[numEmployees] = new Employee;
        employeePtr[numEmployees]->id = oneID;
        strcpy(employeePtr[numEmployees]->name, oneName);
        employeePtr[numEmployees]->hourlyPay = oneHourlyPay;
        employeePtr[numEmployees]->numDeps = oneNumDeps;
        employeePtr[numEmployees]->type = oneType;

        numEmployees++;

        // get next item information
        employeeFile >> oneID;
        employeeFile.get( oneName, 21, '\n' );
        employeeFile >> oneHourlyPay >> oneNumDeps >> oneType;
    }
}

void setTimesheet( ifstream &transFile, TimesheetInfo *timesheetPtr[], int &numTrans)
{
    int   oneID;           // temporary ID to match getID() search
    float oneHoursWorked;  // hours worked


    numTrans = 0;
    transFile >> oneID >> oneHoursWorked;

    while (transFile && numTrans < MAX_NUMBER_OF_EMPLOYEES)
    {
        // move new item into arrays and increment item count
        timesheetPtr[numTrans] = new TimesheetInfo;
        timesheetPtr[numTrans]->transID = oneID;
        timesheetPtr[numTrans]->hoursWorked = oneHoursWorked;

        numTrans++;

        // get next timesheet information
        transFile >> oneID >> oneHoursWorked;
    }


}
fralin
  • 11
  • 2
  • 1
    Consider making `name` a `std::string`. – user4581301 Dec 10 '19 at 20:29
  • In `Employee *employee[...];` storing pointers to the employees makes the code more complex and probably slower. Consider using `std::vector`, but if that's disallowed, `Employee employee[...];` – user4581301 Dec 10 '19 at 20:32
  • *I'm definitely new to C++ and am hoping someone sees something obvious that I'm just missing.* -- You resorted to using pointers, so nothing is "obvious" by merely eyeballing the code. Using containers such as `std::vector` makes the code much more easier to debug and maintain. – PaulMcKenzie Dec 10 '19 at 20:33
  • have a look here too https://stackoverflow.com/questions/19651788/whats-the-meaning-of-exception-code-exc-i386-gpflt – LoneWanderer Dec 10 '19 at 20:35
  • 1
    Popped the code through a compiler with a stack of extra warnings turned on to see it if caught anything. Looks like you're missing `#include` to get `strcpy`. This is rendered a moot point if `name` becomes a `std::string` – user4581301 Dec 10 '19 at 20:36
  • The assignment requires that we use c-strings; I've actually been able to make it work perfectly without the use of pointers using only the seach() and bubbleSort() functions - I'm just trying to better understand pointers and see if I can make the code more modular. Thanks though, I'll see how switching to a vector works for me! – fralin Dec 10 '19 at 20:37
  • `delete [] *employee;` almost certainly isn't doing what you want it to do. You need a loop to release all of the employees one by one. You'll have the same problem with `delete [] *timesheet;`. This could be your reported bug, but probably just a silent failure. – user4581301 Dec 10 '19 at 20:38
  • 1
    To reproduce your error we'll need your input file, but you would be better served by producing a [mcve] and eliminating the need for a file at all. – user4581301 Dec 10 '19 at 20:39
  • 1
    @user4581301 pointed out, the code you provided does not compile. Without the input file or a mockup, we can't do anything for you. Plus, I strongly advise to learn ou to use a proper debugger and execute code step by step and have a look at your variables. – LoneWanderer Dec 10 '19 at 20:40
  • Debuggers are da bomb. They allow you to run the program on your terms, not the GHz of a modern CPU, and see what's happening as it happens. A debugger normally halts when the program signals a fatal event, allowing you to investigate the crash site. The bug that lead to the crash almost always happened earlier, so you take what you learned from the crash and place a few strategic breakpoints to stop the program at potential problems sites and step through the code to see what happens. If it's not what you expected, congratulations! You found a bug. – user4581301 Dec 10 '19 at 20:44
  • If you cannot figure out how to fix what happened, use what you learned from debugging to produce a smaller program, a [mcve], that exposes the bug and does nothing else, then update the code here with the [mcve]. Few bugs survive making a good [mcve], though, because when you have a program that is nothing but bug, it's usually really easy to see what caused it. – user4581301 Dec 10 '19 at 20:48
  • 1
    Right on, thanks so much for the thoughts everyone. Yeah, right after posting it I realized it didn't have the files needed to make it work (and I'd commented out the sections prompting for the paths to speed up the process of running it). I'll dive into the debugger and work on a minimal reproducible example. Thanks again! – fralin Dec 10 '19 at 20:51

0 Answers0