Thread: resolving blocks into functions

  1. #1
    Registered User
    Join Date
    May 2009
    Posts
    242

    resolving blocks into functions

    I apologize in advance for again submitting a lengthy block of code, but I feel somewhat obligated to present the solution that I came up with for the problem posed in the thread "keeping track of code blocks."

    For those who didn't read that one but are willing to wade through a fairly long program, the problem is this: Repeatedly ask for employee number, gross wages, state taxes, fed. taxes, FICA (with various obvious validation rules), then use "0" for employee number as sentinel to end data entry and proceed to a printed report of the totals for all employees together. In Gaddis, 6th ed., it's chap. 5, programming challenge 15. And I added my own additional "challenge" of putting in confirmations at strategic points.

    So, now that I've learned a little about functions, here's my new solution:
    Code:
    // payroll report using functions
    
    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int getEmployee();
    bool confValue(char);
    char getConf();
    double getGross(int);
    double getTax(int, int, double);
    void showTaxTypeLower(int);
    void showTaxTypeUpper(int);
    char confData(int, double, double, double, double);
    
    int main()
    {
    	int Num;
    	double Gross, State, Fed, FICA, TotGross = 0, TotState = 0, TotFed = 0, TotFICA = 0;
    
    	do
    	{
    		Num = getEmployee();
    		if (Num != 0)
    		{
    			do
    			{
    				Gross = getGross(Num);
    				State = getTax(Num, 1, Gross);
    				Fed = getTax(Num, 2, Gross);
    				FICA = getTax(Num, 3, Gross);
    				if (State + Fed + FICA > Gross)
    					cout << "Total taxes cannot exceed gross pay.\n"
    						<< "Re-enter data for employee " << Num << ".\n";
    			}
    			while ((State + Fed + FICA > Gross) || !confValue(confData(Num, Gross, State, Fed, FICA)));
    			TotGross += Gross;
    			TotState += State;
    			TotFed += Fed;
    			TotFICA += FICA;
    		}
    	}
    	while (Num !=0);
    
    	cout << "\nPayroll Report\n\n"
    		<< setprecision(2) << fixed
    		<< "Gross pay total:   $" << setw(12) << right << TotGross << endl
    		<< "State tax total:   $" << setw(12) << TotState << endl
    		<< "Federal tax total: $" << setw(12) << TotFed << endl
    		<< "FICA total:        $" << setw(12) << TotFICA << endl << endl;
    
    	return 0;
    }
    // returns true if answer is Y or y
    bool confValue(char X)
    {
    	if ((X == 'Y') || (X == 'y'))
    		return 1;
    	else
    		return 0;
    }
    // asks for Y/N confirmation
    char getConf()
    {
    	char Conf;
    	cout << "Confirm (Y/N): ";
    	cin >> Conf;
    	return Conf;
    }
    
    // gets valid employee number
    int getEmployee()
    {
    	int Num;
    	do
    	{
    		cout << "Enter employee number or \"0\" to end list: ";
    		cin >> Num;
    
    		// validate
    		while (cin.fail() || Num < 0)
    		{
    			cin.clear();
    			cin.ignore(100, '\n');
    			cout << "Invalid input!\n"
    				<< "Enter employee number or \"0\" to end list: ";
    			cin >> Num;
    		}
    
    		// confirm
    		if (Num > 0)
    			cout << "You wish to enter data for employee " << Num << ".\n";
    		if (Num == 0)
    			cout << "You have finished entering employee data.\n";
    	}
    	while (!confValue(getConf()));
    
    	return Num;
    }
    // get gross pay
    double getGross(int EmpNum)
    {
    	double Gross;
    
    	cout << "Employee " << EmpNum << " gross pay: ";
    	cin >> Gross;
    
    	// validate
    	while (cin.fail() || Gross < 0)
    	{
    		cin.clear();
    		cin.ignore(100, '\n');
    		cout << "Invalid input!\n"
    			<< "Employee " << EmpNum << " gross pay: ";
    		cin >> Gross;
    	}
    	
    	return Gross;
    }
    
    // converts integer into a tax type message; outputs lower case
    void showTaxTypeLower(int Type)
    {
    	switch (Type)
    	{
    	case 1:
    		cout << "state tax";
    		break;
    	case 2:
    		cout << "federal tax";
    		break;
    	default:
    		cout << "FICA";
    	}
    
    }
    // same as TaxTypeLower but in upper case
    void showTaxTypeUpper(int Type)
    {
    	switch (Type)
    	{
    	case 1:
    		cout << "State tax";
    		break;
    	case 2:
    		cout << "Federal tax";
    		break;
    	default:
    		cout << "FICA";
    	}
    }
    
    // get values for various taxes
    double getTax(int EmpNum, int Type, double Gross)
    {
    	double Tax;
    
    	cout << "Employee " << EmpNum << " ";
    	showTaxTypeLower(Type);
    	cout << ": ";
    	cin >> Tax;
    
    	// validate
    	while (cin.fail() || Tax < 0 || Tax > Gross)
    	{
    		cin.clear();
    		cin.ignore(100, '\n');
    		cout << "Invalid input!\n";
    		if (Tax < 0)
    		{
    			showTaxTypeUpper(Type);
    			cout << " cannot be negative.\n";
    		}
    		if (Tax > Gross)
    		{
    			showTaxTypeUpper(Type);
    			cout << " cannot exceed gross pay.\n";
    		}
    		cout << "Employee " << EmpNum << " ";
    		showTaxTypeLower(Type);
    		cout << ": ";
    		cin >> Tax;
    	}
    	
    	return Tax;
    }
    
    // confirms data after entry
    char confData(int Num, double Gross, double State, double Fed, double FICA)
    {
    	cout << setprecision(2) << fixed
    		<< "Wages and taxes for employee " << Num << ":\n"
    		<< "  Gross wages: $" << setw(10) << right << Gross << endl
    		<< "  State tax:   $" << setw(10) << State << endl
    		<< "  Federal tax: $" << setw(10) << Fed << endl
    		<< "  FICA:        $" << setw(10) << FICA << endl;
    
    	return getConf();
    }
    Critique is much appreciated, but bear in mind that I'm working with a very limited vocabulary in the language at this point.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Good job.
    That looks a lot better than the previous version.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    242
    tx, I think the whole functions thing ended up cleaning up the logic of the program as well, because with the resolution into functions, I could finally see pretty easily where I was actually at in the various loops.

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Aisthesis View Post
    tx, I think the whole functions thing ended up cleaning up the logic of the program as well, because with the resolution into functions, I could finally see pretty easily where I was actually at in the various loops.
    I think you did a great job as well. There is an additional simplification you can make to one of the loops, which removes another level of bracing.

    Instead of this:

    Code:
    	do
    	{
    		Num = getEmployee();
    		if (Num != 0)
    		{
    			do
    			{
    				Gross = getGross(Num);
    				State = getTax(Num, 1, Gross);
    				Fed = getTax(Num, 2, Gross);
    				FICA = getTax(Num, 3, Gross);
    				if (State + Fed + FICA > Gross)
    					cout << "Total taxes cannot exceed gross pay.\n"
    						 << "Re-enter data for employee " << Num << ".\n";
    			}
    			while ((State + Fed + FICA > Gross) || !confValue(confData(Num, Gross, State, Fed, FICA)));
    			TotGross += Gross;
    			TotState += State;
    			TotFed += Fed;
    			TotFICA += FICA;
    		}
    	}
    	while (Num !=0);
    What about this:

    Code:
    	for( Num = getEmployee(); Num != 0; Num = getEmployee() )
    	{
    		do
    		{
    			Gross = getGross(Num);
    			State = getTax(Num, 1, Gross);
    			Fed = getTax(Num, 2, Gross);
    			FICA = getTax(Num, 3, Gross);
    			if (State + Fed + FICA > Gross)
    				cout << "Total taxes cannot exceed gross pay.\n"
    					 << "Re-enter data for employee " << Num << ".\n";
    		}
    		while ((State + Fed + FICA > Gross) || !confValue(confData(Num, Gross, State, Fed, FICA)));
    		TotGross += Gross;
    		TotState += State;
    		TotFed += Fed;
    		TotFICA += FICA;
    	}
    EDIT: Are you sure you haven't done this before? This is actually quite good.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I agree, it does look pretty good.

    One possible stylistic improvement would be to include the parameter names in your function declarations. Although they are unnecessary for function prototypes, they can help to indicate what the parameters are for.

    Another possible improvement, again a matter of style, would be to change this:
    Code:
    // returns true if answer is Y or y
    bool confValue(char X)
    {
    	if ((X == 'Y') || (X == 'y'))
    		return 1;
    	else
    		return 0;
    }
    to:
    Code:
    // returns true if answer is Y or y
    bool confValue(char Value)
    {
    	return (Value == 'Y') || (Value == 'y');
    }
    Personally, I feel that the relative precedence of == and || are generally well known and hence the parentheses should be left out to remove noise, but if you feel that the parentheses should be present as they remove all possible ambiguity, that is fine.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Void Functions Help
    By bethanne41 in forum C++ Programming
    Replies: 1
    Last Post: 05-09-2005, 05:30 PM
  2. Functions and Classes - What did I do wrong?
    By redmage in forum C++ Programming
    Replies: 5
    Last Post: 04-11-2005, 11:50 AM
  3. calling functions within functions
    By edd1986 in forum C Programming
    Replies: 3
    Last Post: 03-29-2005, 03:35 AM
  4. Factory Functions HOWTO
    By GuardianDevil in forum Windows Programming
    Replies: 1
    Last Post: 05-01-2004, 01:41 PM
  5. Shell functions on Win XP
    By geek@02 in forum Windows Programming
    Replies: 6
    Last Post: 04-19-2004, 05:39 AM