Assignment:

  1. Print the following heading at the top of the output page: Miser Corporation Payroll

  2. Read an unknown number of employee data records as shown below. Each group of data will contain an employee's name, hours worked, rate of page and age. A typical group of data will be:

    Duck, Donald 45 3.25 51

    Print the data as it is read in, together with appropriate messages (e.g., the name is... the rate of pay is... etc.).

  3. For each employee, compute and print the employee's base pay, which includes overtime (paid at one and a half times the normal rate) for each hour over 40. For example, if an employee earning $20.00 per hour works for 48 hours, then she will be paid for 40 hours at her normal rate plus 8 extra hours at $30.00 (one and a half times $20.00).

  4. For each employee compute the tax paid by the employee, according to this formula: If the employee is 55 years old (or order), then the employee pays tax at a rate of 50% of the base pay; if the employee is below 55, then the tax is 10% of the base pay. Print the tax and the net pay after taxes.

  5. Repeat this process until you have read the last employee. You must decide how to detect the end of the data (you should explain your method in a comment).

  6. Print the name and age of the oldest employee. Do the same for the youngest employee.

  7. Print the name and taxes of the employee who paid the most in taxes.

  8. Print an alphabetically sorted list of all the company's employees.

  9. Print a list of the employees sorted by net pay.

  10. After all your results have been printed, print a message saying that the payroll program is complete.

Code:

//============================================================================
// Assignment  :  Homework #3
// Date        :  11 Mar 2012
//============================================================================

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

const int NAME_SIZE = 51;

struct records {
public:
    char name[NAME_SIZE];
    int hours;
    double rate;
    int age;
    double basepay;
    double tax;
    double netpay;
};

int main() {

    cout << "tttMiser Corporation Payrolln" << endl;

    ifstream datafile; // Declare input file
    datafile.open("datafile.txt", ios::in); // Open input file

    // Check for error opening input file
    if (datafile.fail())
    {
        cout << "Error opening file; program halted." << endl;
        return 0;
    }

    records employee;

    datafile.read(reinterpret_cast<char *>(&employee),sizeof(employee));
    while (!datafile.eof()){
        cout << "Name:t" << employee.name << endl;
        cout << "Hours worked:t" << employee.hours << endl;
        cout << "Rate of pay:t" << employee.rate << endl;
        cout << "Age:t" << employee.age << endl;
        cout << endl;
        datafile.read(reinterpret_cast<char *>(&employee),sizeof(employee));
    }

    datafile.close(); // Close input file
    cout << "The payroll program is complete.";
    return 0; // Close main program function
}

Output:

> Miser Corporation Payroll
> 
> Name: Duck, Donald
> 45.0  3.50    60
> Mouse, Mickey
> 35    6.50    55
> Brown, Charlie
> 35    3.00    20
> Oyle, Olive
> 40    4.50
> Hours worked: 1853321074
> Rate of pay:  6.80457e+199
> Age:  892537445
> 
> Name:     60
> Man, He
> 45    7.50    20
> Ra, She
> 40    3.50    20
> Jetson, George
> 45    3.50    55
> Starr, Brenda
> 35    8.40    60
> Wom
> Hours worked: 1701278319
> Rate of pay:  1.82918e-76
> Age:  171259145
> 
> The payroll program is complete.

Edited 1 Year Ago by Dani: Personal info snipped

Output had indents and stuff but I don't know how to show it as plain text....

Hey so what the hell do I do! I feel like the size thing is screwing it up, but I NEED to put a size, and I don't even know what friggen size to put.

Modify your structure to reflect ONLY what you are reading in from the text file. That is, get rid of the variables in the struct that are NOT found in the text file. Next, get rid of the ifstream.read statements. Only use the open and eof functions. In the eof loop do something like this:

datafile >>  employee.name ;
 cout <<  employee.name  << endl;

 datafile >>  employee.name ;
 cout <<  employee.name  << endl;   


 datafile >>  employee.hours ;
 cout <<  employee.hours  << endl;      
datafile >>  employee.rate ;
 cout <<  employee.rate  << endl;       
datafile >>  employee.age ;
 cout <<  employee.age  << endl;

Ok. So I haven't downloaded and compiled your program or anything like tha, but here's what I think is going on. First the file has five data fields per line: last name, first name, hours worked, pay rate and age. The records class has 7 member values. So when you try to read the file using the read() method of streams read() reads in enough data to try to fill 7 member variables, thereby overreading each line as you go through the file getting things all out of whack and screwing up your output. I would redesign the records class to read in the 5 fields that each line in the file contains. The trick however, is that you have one field that is comma separated and the others are whitespace separated. So, I would probably use a series of input methods, mixing getline() with >> (making sure I clear the input buffer before each call to getline()) rather than trying to use read().

Makes sense, Bob, thanks. I'll start there, then try implementing Lerner's method, which also makes sense, thanks guys, I was just a little scattered.... just a little.....

NOTHING WILL WORK. Closest I can get is the first dude repeated over and over again FOREVER. Updated code:

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

class Records {
public:
    string name;
    double hours;
    double rate;
    int age;
    /*double basepay;
    double tax;
    double netpay;*/
};

int main() {
    Records employee;

    cout << "\t\t\tMiser Corporation Payroll\n" << endl;

    ifstream datafile; // Declare input file
    datafile.open("datafile.txt"); // Open input file

    // Check for error opening input file
    if (!datafile)
    {
        cout << "Error opening file; program halted." << endl;
        exit(1);
    }

    getline(datafile,employee.name);
    datafile >> employee.hours >> employee.rate >> employee.age;
    do {
        cout << "Name: " << employee.name << endl;
        cout << "Hours worked: " << employee.hours << endl;
        cout << "Rate of pay: " << employee.rate << endl;
        cout << "Age: " << employee.age << endl;
        getline(datafile,employee.name);
        datafile >> employee.hours >> employee.rate >> employee.age;
    } while (!datafile.eof());

    datafile.close(); // Close input file
    cout << "The payroll program is complete.";
    return 0; // Close main program function
}

Maybe try something more along the lines of this...

if (datafile.fail())
    {
        cout << "Error opening file; program halted." << endl;
        return 0;
    }
    records employee = {0};
    while(datafile >> employee.name)
    {
        cout <<  employee.name  << endl;
        datafile >>  employee.name ;
        cout <<  employee.name  << endl;    
        datafile >>  employee.hours ;
        cout <<  employee.hours  << endl;       
        datafile >>  employee.rate ;
        cout <<  employee.rate  << endl;        
        datafile >>  employee.age ;
        cout <<  employee.age  << endl;     
    }

    datafile.close(); // Close input file

getline(datafile,employee.name);
datafile >> employee.hours >> employee.rate >> employee.age;

The first line reads as many chars as there is in the file until a new line char is found. You don't want that. I think you want to read the last name only, so you can alphabetize the structs by name as a later part of the project. Either read in the first name and comma as demonstrated by BobS037 and strip of the comma or use getline with comma as the delimeter and let getline strip it for you. If you use getline to do the dirty work, then you need to be sure you have a clean input buffer before you call it because you will probably be using >> to extract the fields in the rest of the line.

How do I make sure I have a clean input buffer before calling getline. Exactly how, because I really don't know about buffers. Also I do want to just stick with the whole name/line, i.e., last comma first; works for me. Sorting the employees alphabetically by name shouldn't pose a problem, since I would still be able to sort them alphabetically by last name, which is what I'd be doing anyway... But my major issue is the closest I can get this to working is to have it read in the first dude once or twice or once but just his name and the remaining values are 0's or it goes on forever reading the same guy (and the name only the first time). What do I do. This is driving me nuts.

The problem is the name fields which are posted as last name followed by a comma, followed by a space followed by first name. If there was no space between last and first name, then you could use >> to get both first and last name in the same field. As it is, if you want to get both last and first name into the same variable as you read in the file contents then you need to come up with some other way. For example you could read in the entire line using getline() with the default new line char as the delimiter. Then you could search for the position of the second space in the line and create a substring from the first char to the position of the second space. But then you'd need to change the values of the remaining data in the input sting/line from char to numerical types. Doable but more of a hassle than it's worth, unless that's you want you want/need to do.

To clear the input buffer you use the ignore() method of input streams. ignore() takes two values, the first being how many char to ignore and the second being what char to be the last char to ignore. The values you put in the () are up to you. By default the values are 1 and newline char. That's often adequate, but to be more robust you can use something bigger than 1, say 1080. To be the most sophisticated you include the limits header and the ios header and then you can ignore the maximum number of char in the input buffer as implemented by your compiler, but that gets a bit overblown for most newbie purposes.

so I would:
ignore(1080);
getline(lastName);

firstname;
hoursWorked;
payRate;
age;
using the appropriate string types, streams, etc.

The problem is the name fields which are posted as last name followed by a comma, followed by a space followed by first name. If there was no space between last and first name, then you could use >> to get both first and last name in the same field. As it is, if you want to get both last and first name into the same variable as you read in the file contents then you need to come up with some other way. For example you could read in the entire line using getline() with the default new line char as the delimiter. Then you could search for the position of the second space in the line and create a substring from the first char to the position of the second space. But then you'd need to change the values of the remaining data in the input sting/line from char to numerical types. Doable but more of a hassle than it's worth, unless that's you want you want/need to do.

To clear the input buffer you use the ignore() method of input streams. ignore() takes two values, the first being how many char to ignore and the second being what char to be the last char to ignore. The values you put in the () are up to you. By default the values are 1 and newline char. That's often adequate, but to be more robust you can use something bigger than 1, say 1080. To be the most sophisticated you include the limits header and the ios header and then you can ignore the maximum number of char in the input buffer as implemented by your compiler, but that gets a bit overblown for most newbie purposes.

so I would: ~~~
ignore(1080);
getline(lastName);

firstname;
hoursWorked;
payRate;
age;~~~
using the appropriate string types, streams, etc.

The problem is the name fields which are posted as last name followed by a comma, followed by a space followed by first name. If there was no space between last and first name, then you could use >> to get both first and last name in the same field. As it is, if you want to get both last and first name into the same variable as you read in the file contents then you need to come up with some other way. For example you could read in the entire line using getline() with the default new line char as the delimiter. Then you could search for the position of the second space in the line and create a substring from the first char to the position of the second space. But then you'd need to change the values of the remaining data in the input sting/line from char to numerical types. Doable but more of a hassle than it's worth, unless that's you want you want/need to do.

To clear the input buffer you use the ignore() method of input streams. ignore() takes two values, the first being how many char to ignore and the second being what char to be the last char to ignore. The values you put in the () are up to you. By default the values are 1 and newline char. That's often adequate, but to be more robust you can use something bigger than 1, say 1080. To be the most sophisticated you include the limits header and the ios header and then you can ignore the maximum number of char in the input buffer as implemented by your compiler, but that gets a bit overblown for most newbie purposes.

so I would: '\n'
ignore(1080);
getline(lastName);

firstname;
hoursWorked;
payRate;
age;'\n'
using the appropriate string types, streams, etc.

The problem is the name fields which are posted as last name followed by a comma, followed by a space followed by first name. If there was no space between last and first name, then you could use >> to get both first and last name in the same field. As it is, if you want to get both last and first name into the same variable as you read in the file contents then you need to come up with some other way. For example you could read in the entire line using getline() with the default new line char as the delimiter. Then you could search for the position of the second space in the line and create a substring from the first char to the position of the second space. But then you'd need to change the values of the remaining data in the input sting/line from char to numerical types. Doable but more of a hassle than it's worth, unless that's you want you want/need to do.

To clear the input buffer you use the ignore() method of input streams. ignore() takes two values, the first being how many char to ignore and the second being what char to be the last char to ignore. The values you put in the () are up to you. By default the values are 1 and newline char. That's often adequate, but to be more robust you can use something bigger than 1, say 1080. To be the most sophisticated you include the limits header and the ios header and then you can ignore the maximum number of char in the input buffer as implemented by your compiler, but that gets a bit overblown for most newbie purposes.

so I would: '\n'
ignore(1080);
getline(lastName);

firstname;
hoursWorked;
payRate;
age;'\n'
using the appropriate string types, streams, etc.

Frustrating not getting the board to do what I want. Oh, well. I would use ignore with a relatively large number, followed by getline using comma as the delimiting char, followed by serial calls to >> to get the other fields in the line.

This article has been dead for over six months. Start a new discussion instead.