Need help with User-Defined Functions and Looping

My professor gave us an assignment to work out a payroll program that takes in data from a file, then outputs the payroll information in one file and the errors in another file. I can get the error file working fine, but Im having trouble getting the info to send to the payroll.

I have tried tracing the errors with cout's and I find that within my WHILE loop I never make it into the nested FOR loop. It runs the GetData function, and then just ends the program, and never makes it to my calculations or sending to my payroll file.

I have included the whole program for context, but I really only would like help for the specific problems listed above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;

void GetData(ifstream &, ofstream &, string &, string &, float &, float &, int &, char &, float &, float &, int &, char &);
float Gross(float wage, float hours);
float FITW(float gross, int exemp, char status);
float FICA(float gross);
void SendData(ofstream &, string, string, float, float, float, float, float, float);

int main()
{
	ifstream infile;
	ofstream Outfile;
	ofstream errorfile;

	string firstName, lastName;
	float wage, hours, hold, gross, tax, net, wageError, hourError;
	int exemp, exempError;
	char status, statusError;

	cout << "Start of program." << endl;

	cout << "Opening infile..." << endl;
	infile.open("emp.txt");

	if (!infile)
	{
		cout << "Cannot open file. Terminating program." << endl;
		exit(1);
	}
	else
	{
		cout << "File opened successfully." << endl;
	}

	cout << "Opening outfile..." << endl;
	Outfile.open("pay.txt");

	if (!Outfile)
	{
		cout << "Cannot open file. Terminating program." << endl;
		exit(1);
	}
	else
	{
		cout << "File opened successfully." << endl;
	}

	cout << "Opening errorfile..." << endl;
	errorfile.open("error.txt");

	if (!errorfile)
	{
		cout << "Cannot open file. Terminating program." << endl;
		exit(1);
	}
	else
	{
		cout << "File opened successfully." << endl;
	}

	while (!infile.eof())
	{
		GetData(infile, errorfile, firstName, lastName, wage, hours, exemp, status, wageError, hourError, exempError, statusError);
		if (!exempError && !statusError && !wageError && hourError)
		{
			gross = Gross(hours, wage);
			cout << gross << endl;
			tax = FICA(gross);
			cout << tax << endl;
			hold = FITW(gross, exemp, status);
			cout << hold << endl;
			net = gross - tax - hold;
			cout << net << endl;
			SendData(Outfile, firstName, lastName, hours, wage, gross, net, tax, hold);
		}
	}

	cout << "End" << endl;

	infile.close();
	errorfile.close();
	return 0;

}

/*****************************************************/

void GetData(ifstream & infile, ofstream & errorfile, string & firstName, string & lastName, float & wage, float & hours, int & exemp, char & status, float & wageError, float & hourError, int & exempError, char & statusError)
{
	infile >> firstName >> lastName >> wage >> hours >> exemp >> status;
	wageError = wage <= 0;
	hourError = hours < 0;
	exempError = exemp < 0;
	statusError = (status < 'M' || status > 'M' && status < 'S' || status > 'S' && status < 'm' || status > 'm' && status < 's' || status > 's');
	if (statusError)
	{
		cout << "Marital status error for: " << firstName << " " << lastName << " " << wage << " " << hours << " " << exemp << " " << status << endl;
		errorfile << "Marital status error for: " << firstName << " " << lastName << " " << wage << " " << hours << " " << exemp << " " << status << endl;
	}
	if (wageError)
	{
		cout << "Wage error for: " << firstName << " " << lastName << " " << wage << " " << hours << " " << exemp << " " << status << endl;
		errorfile << "Wage error for: " << firstName << " " << lastName << " " << wage << " " << hours << " " << exemp << " " << status << endl;
	}
	if (hourError)
	{
		cout << "Hour error for: " << firstName << " " << lastName << " " << wage << " " << hours << " " << exemp << " " << status << endl;
		errorfile << "Hour error for: " << firstName << " " << lastName << " " << wage << " " << hours << " " << exemp << " " << status << endl;
	}
	if (exempError)
	{
		cout << "Exemption error for: " << firstName << " " << lastName << " " << wage << " " << hours << " " << exemp << " " << status << endl;
		errorfile << "Exemption error for: " << firstName << " " << lastName << " " << wage << " " << hours << " " << exemp << " " << status << endl;
	}
}

/*****************************************************/

float Gross(float wage, float hours)
{
	return (wage*hours);
	if (hours > 40)
		return (wage * 40 + (hours - 40)*1.5*wage);
}

/*****************************************************/

float FITW(float gross, int exemp, char status)
{
	double income;
	income = gross - (exemp*73.08);
	if ((income <= 721) && (status == 'S' || 's'))
		return (0);
	else if ((income>721 && income <= 7510) && (status == 'S' || 's'))
		return ((income - 721)*0.28 + 93.60);
	else
		return ((income - 7510)*0.35 + 2167.16);


	if ((income <= 1515) && (status == 'M' || 'm'))
		return (0);
	else if ((income>1515 && income <= 7624) && (status == 'M' || 'm'))
		return ((income - 1515)*0.15 + 187.15);
	else
		return ((income - 7624)*0.30 + 2020.42);
}

/*****************************************************/

float FICA(float gross)
{
	const float FICAtax = 0.0565;
	return (gross*FICAtax);
}

/*****************************************************/

void SendData(ofstream & Outfile, string firstName, string lastName, float hours, float wage, float net, float gross, float tax, float hold)
{
	Outfile.open("pay.txt");
	Outfile << fixed << showpoint << setprecision(2);
	Outfile << "Payroll for: " << firstName << lastName << endl;
	Outfile << "Hours worked: " << hours << endl;
	Outfile << "Hourly wage: " << wage << endl;
	Outfile << "Gross pay: " << gross << endl;
	Outfile << "FICA Tax: " << tax << endl;
	Outfile << "Federal Income Tax Witheld: " << hold << endl;
	Outfile << "Net Amount: " << net << endl;
	Outfile << endl;
	Outfile.close();
}
Line 68
 
if (!exempError && !statusError && !wageError && hourError)


I think you mean
 
if (!exempError && !statusError && !wageError && !hourError)


Also, might I suggest you pack your data into a struct. GetData has 12 parameters which is a bit too many. C++ lets you have as many parameters as you want but having more than 4 is a bit too many. GetData should return a struct containing all of the data and throw exceptions.

You could have four exception classes for each type of error you might find in the data. GetData will throw them up to main where they will be caught and handled. This means that the new signature could be

PayrollData GetData(ifstream &)

I'd be glad to answer further questions.
Oh wow, I cant believe I missed that, lol.

So now the program runs, but Im having trouble with it outputting data to my pay.txt file.

There should be multiple entries for several different employees, but its only picking up the last entry?
Maybe your program would be easier to debug if you refactor it. Break down your huge functions into little ones. Then you can check that each little function is behaving correctly. If all of your little functions are behaving correctly then the whole program will behave correctly.

In main there are three sections of code that look pretty much identical. They all look like this:

1
2
3
4
5
6
7
8
9
10
11
12
cout << "Opening infile..." << endl;
infile.open("emp.txt");

if (!infile)
{
	cout << "Cannot open file. Terminating program." << endl;
	exit(1);
}
else
{
	cout << "File opened successfully." << endl;
}


Lets put this duplicate code into a function.

1
2
3
4
5
6
7
8
9
10
11
template <typename Stream>
Stream openFile(const char *path) {
  Stream stream(path);
  if (stream.is_open()) {
    std::cout << '\"' << path << "\" opened successfully\n";
    return stream;
  } else {
    std::cout << "Cannot open file \"" << path << "\"\n";
    exit(1);
  }
}


Then in main you could do this.

1
2
3
auto infile = openFile<std::ifstream>("emp.txt");
auto outfile = openFile<std::ofstream>("pay.txt");
auto errorfile = openFile<std::ofstream>("error.txt");


Another thing you could do is increase your compiler warning level. The if statement at line 126 inside the Gross function will never be reached because there is a return statement before it.

If you're using clang or GCC then pass these options to your compiler.

-Wall -Wextra -Weffc++ -Wpedantic

With these options enabled your compiler should tell you about problems similar to the one in Gross
One more thing you could do is define constants. For example in Gross. Your calculating the pay of the employee based on hours worked and wages. If the employer works over 40 hours then they get time and a half. But what if you want to change that to 35 hours or 45 hours? Well you would have to look for every 40 in the code and replace it with 35.

At the very beginning of your program you could put something like
 
const float OVERTIME = 40.0f;


Now that 40 has a name and meaning. There's now one place where you can change the overtime threshold. This makes the code more readable, easier to change and less error prone.

The new function becomes
1
2
3
4
5
6
7
float Gross(const float wage, const float hours) {
  if (hours > OVERTIME) {
    return wage * OVERTIME + (hours - OVERTIME) * 1.5f * wage;
  } else {
    return wage * hours;
  }
}
I appreciate the help, however a lot of the suggestions youre giving use code we have yet to go over.

I have tried to fix my Gross function however Im still having trouble.

What its supposed to do is check the hours, and if the hours are greater than 40 do one formula and if they are less than 40 do another, but they seem to always do the second formula regardless. I even tried flipping it to check for <=40 and it still only does the gross = return * wage formula.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
float Gross(float wage, float hours)
{
	float gross;
	if (hours > 40)
	{
		gross = (40 * wage + (hours - 40)*(1.5*wage));
		return gross;
	}
	else
	{
		gross = hours * wage;
		return gross;
	}
}
Have you passed in an hours value that you know is greater than 40 and put a std::cout in the Gross function?

Comment out your entire main function and put in

std::cout << Gross(20, 50) << '\n';

Then in Gross you could put a std::cout in each of the branches.
Last edited on
This is the data that Im working with (First Name, Last Name, Wage, Hours, Exemptions, Status)

Al Clark	38	45.5	4	M
Joyce Itin	120	77	3	M
Vahid Hamidi	15	25	3	M
Melody Jung	27	60.6	1	M
Joahn Garcia	-25	-3	-3	M
Vera Moroz	23	72	3	N
Robert Innes	19.85	40	1	S
Mark Armstrong	-25	23	5	M
Ashton Williams	15	15.69	-6	S
Angela Klein	0	54.32	6	S
Jerry Smith	168.5	36.5	2	S
Leslie McHenry	68	95.63	1	S
Morgan Stock	72	99	2	S
Nick Lee	15	5	1	S
Mary Jones	45	75.36	2	S


I have tested it with each appropriate piece of data and it doesnt work for each one that has over 40 hours.

I thought first that maybe it was that I was only picking up the first or the last set of data, which I have had trouble with in the past when inputting data from files, but that cant be it since both the first and last sets have hours greater than 40.

And it would also appear my GetData is working ok since when I try doing a cout with the data to see if its put in the right place it appears to be. So Im really confused.
You're Gross function looks like it behaves correctly. Somehow the code that passes input to Gross must be changing the data.
Perhaps you could trace the input to Gross from GetData with std::cout
I tried to figure it out and when I do couts with only the getdata and gross I get this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Start of program.
Opening infile...
File opened successfully.
Opening outfile...
File opened successfully.
Opening errorfile...
File opened successfully.
Al Clark 38 45.5 4 M
Gross: 1729
Joyce Itin 120 77 3 M
Gross: 12320
Vahid Hamidi 15 25 3 M
Gross: 375
Melody Jung 27 60.6 1 M
Gross: 1636.2
Wage error for: Joahn Garcia -25 -3 -3 M
Hour error for: Joahn Garcia -25 -3 -3 M
Exemption error for: Joahn Garcia -25 -3 -3 M
Marital status error for: Vera Moroz 23 72 3 N
Robert Innes 19.85 40 1 S
Gross: 794
Wage error for: Mark Armstrong -25 23 5 M
Exemption error for: Ashton Williams 15 15.69 -6 S
Wage error for: Angela Klein 0 54.32 6 S
Jerry Smith 168.5 36.5 2 S
Gross: 8495.38
Leslie McHenry 68 95.63 1 S
Gross: 7841.66
Morgan Stock 72 99 2 S
Gross: 8712
Nick Lee 15 5 1 S
Gross: 75
Mary Jones 45 75.36 2 S
Gross: 3579.6
Mary Jones 45 75.36 2 S
Gross: 3579.6
End
Press any key to continue . . .


So it looks to me like it picks up the correct data (even tho it does pick up Mary Jones twice but that is not the focus of my concern right now), but somehow its not getting to that formula.
You're passing the arguments in the wrong order. Line 70 is
 
gross = Gross(hours, wage);


But the signature of Gross is
 
float Gross(float wage, float hours);


The easiest way to avoid this problem would be to rename Gross to something that describes the order of the parameters like CalcGrossFromWageAndHours or GrossWageHours.
Oh thank you so much!
I didnt even realize I had them in different orders.

Everything seems to be flowing correctly now, but Im still having a slight problem with the last set of data repeating itself.
Topic archived. No new replies allowed.