Thread: keeping track of code blocks

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

    keeping track of code blocks

    In some (for me) longish programs that include some nested loops and if/else if/ else statements, I was having to scroll around quite a bit (even with canonical indentations) to figure out just what the various blocks were doing and whether I had the right number of brackets.

    So, my spontaneous solution has been to immediately close an empty block with a bracket and a note describing what the block does. Example without any real code yet:

    Code:
    // loop for entering and validating Var
    do
    {
    }
    while (Val == 0); // closes do-while loop for entering and validating Var
    After doing that, then I start writing the code inside the loop.

    This seems to help (as a supplement to correct indentation practices), but I wondered if others have better suggestions. I thought this was another one worth asking as newbie just to try to develop good programming habits early.

  2. #2
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    I did that too, although newer IDEs usually add the closing brace for you automagically. What IDE are you using?

    The other thing you should do is keep your functions small and to the point. A function should do a single thing and do it well.
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Generally, if I can't see the opening and closing brace on the screen at the same time, I refactor the loop until I can. Deep nesting can almost always be resolved that way. Occasionally some performance-critical chunk of code needs to be long, but that's the exception, and even in that case it rarely nests more than two or three levels deep.

    As for typing both the opening and closing braces at the same time before coding the body of the loop, that's great practice and pretty universal. But adding a comment to indicate which block is being closed is really a hint that you should break the code out.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Beyond simply factoring out code into other functions, preferring RAII, placing sentries at the correct level, and other generalities, some situations have specific ways to simplify nesting depth. (For example, propagating errors from immediate levels while returning to the parent block on success will sometimes clear a few levels.) Odds are if you are dealing with something *you've* written and resort to scrolling around you probably need a different approach to the problem you are trying to solve. (Or you need a reboot.) You could always ask for help with what you're doing now...

    Soma

  5. #5
    Weak. dra's Avatar
    Join Date
    Apr 2005
    Posts
    166
    Quote Originally Posted by brewbuck View Post
    Generally, if I can't see the opening and closing brace on the screen at the same time, I refactor the loop until I can.
    Depends on how big your screen is!

  6. #6
    Registered User
    Join Date
    May 2009
    Posts
    23
    what kind of screen do you think is suitable for it

  7. #7
    Registered User
    Join Date
    May 2009
    Posts
    242
    As to IDE, I'm using MS Visual C++ Express. I also have Borland's Turbo C++ but couldn't figure out how to use it yet (I'm just developing 1 .cpp file at a time, and Borland, at least as far as I can tell at my currently primitive level, seems almost require that you know how to navigate around a project containing multiple .cpp code files, etc. I did notice that Borland fills in more than MS).

    The problem may be the result of getting over-ambitious on exercises where I've tried to go beyond what "the book" (Gaddis, up to and including chap. 5) clearly wants on the exercise. For example, I'm imposing more strict validation than he presumably wants at this point (hence a previous question here), and I'm asking the user to confirm entries at certain strategic points in the program.

    And... well, if you guys want to see some code, here goes. I won't claim that it's optimal efficiency, even restricting oneself to the portions of the language I currently know, but it does produce pretty much the desired result, and I can't see how to make the somewhat complex loop structure significantly more efficient with the stuff I know. But maybe you guys will see something I don't.

    Here's the task (Gaddis, chap. 5, prog. challenge 15): Display a weekly payroll report given data for employee number, gross pay, state tax, federal tax, and FICA with various validations for gross pay and taxes (should be obvious from my code). Also, entering employee number 0 should act as a sentinel to terminate data entry and display the payroll report.

    Here's my solution:
    Code:
    // payroll report
    
    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int main()
    {
    	int Num;
    	double Gross, TotGross = 0, State, TotState = 0, Fed, TotFed = 0,
    		FICA, TotFICA = 0;
    	bool Val = 0;
    	char Conf = 'n';
    
    	do
    	{ 
    // get employee number
    		do
    		{
    			cout << "Enter employee number or \"0\" to end list: ";
    			cin >> Num;
    	// validate input
    			while (cin.fail() || (Num < 0))
    			{
    				cin.clear();
    				cin.ignore(100, '\n');
    				cout << "Invalid input!\n\n"
    					<< "Enter employee number or \"0\" to end list: ";
    				cin >> Num;
    			}
    	// exit loop on 0 entry for employee number
    			if (Num == 0)
    			{
    				cout << "\nAre you finished entering employee data (Y/N)? ";
    				cin >> Conf;
    			}
    			if ((Num == 0) && ((Conf == 'Y') || (Conf == 'y')))
    				Val = 1;
    			else if (Num == 0)
    				cout << endl; // mistaken 0 entry
    			else
    			{
    	// confirm employee number
    				cout << "Employee number is " << Num
    					<< ". \nConfirm (Y/N): ";
    				cin >> Conf;
    				cout << endl;
    		// get info only when confirmed; otherwise rerun employee num entry loop
    				if ((Conf == 'Y') || (Conf == 'y'))
    				{
    					do
    					{
    		// gross pay
    						cout << "Employee " << Num << " gross pay: ";
    						cin >> Gross;
    			// validate
    						while (cin.fail() || (Gross < 0))
    						{		
    							cin.clear();
    							cin.ignore(100, '\n');
    							cout << "Invalid input!\n\n"
    								<< "Employee " << Num << " gross pay: ";
    							cin >> Gross;
    						}
    			
    		// state tax
    						cout << "\nEmployee " << Num << " state tax: ";
    						cin >> State;
    			// validate
    						while (cin.fail() || (State < 0) || (State > Gross))
    						{		
    							cin.clear();
    							cin.ignore(100, '\n');
    							cout << "Invalid input!\n";
    							if (State < 0)
    								cout << "State tax cannot be negative.\n";
    							if (State > Gross)
    								cout << "State tax cannot exceed gross wages.\n";
    							cout << "Employee " << Num << " state tax: ";
    							cin >> State;
    						}
    			
    		// federal tax
    						cout << "\nEmployee " << Num << " federal tax: ";
    						cin >> Fed;
    			// validate 
    						while (cin.fail() || (Fed < 0) || (Fed > Gross))
    						{		
    							cin.clear();
    							cin.ignore(100, '\n');
    							cout << "Invalid input!\n";
    							if (Fed < 0)
    								cout << "Federal tax cannot be negative.\n";
    							if (Fed > Gross)
    								cout << "Federal tax cannot exceed gross wages.\n";
    							cout << "Employee " << Num << " federal tax: ";
    							cin >> Fed;
    						}
    			
    		// FICA
    						cout << "\nEmployee " << Num << " FICA: ";
    						cin >> FICA;
    
    			// validate
    						while (cin.fail() || (FICA < 0) || (FICA > Gross))
    						{		
    							cin.clear();
    							cin.ignore(100, '\n');
    							cout << "Invalid input!\n";
    							if (FICA < 0)
    								cout << "FICA cannot be negative.\n";
    							if (FICA > Gross)
    								cout << "FICA cannot exceed gross wages.\n";
    							cout << "Employee " << Num << " FICA: ";
    							cin >> FICA;
    						}
    			
    		// validate
    						if (State + Fed + FICA > Gross)
    						{
    							cout << "Total taxes cannot exceed gross wages.\n"
    								<< "Re-enter data for employee " << Num << ".\n";
    							Val = 0;
    						}
    		// confirm
    						else
    						{
    							cout << setprecision(2) << fixed
    								<< "Wages and taxes for employee " << Num << ":\n"
    								<< "  Gross wages: $" << setw(10) << right << Gross << endl
    								<< "  State tax:   $" << setw(10) << right << State << endl
    								<< "  Federal tax: $" << setw(10) << right << Fed << endl
    								<< "  FICA:        $" << setw(10) << right << FICA << endl
    								<< "Confirm (Y/N): ";
    							cin >> Conf;						
    							if ((Conf == 'Y') || (Conf == 'y'))
    							{
    								Val = 1;
    								cout << endl;
    							}
    							else
    							{
    								Val = 0;
    								cout << "Re-enter data for employee " << Num << ".\n";
    							}
    						}
    
    					}
    					while (Val == 0); // ends do loop for specific data after confirmation of employee number
    
    		// update accumulators
    					TotGross += Gross;
    					TotState += State;
    					TotFed += Fed;
    					TotFICA += FICA;
    					Val = 0;
    				}	
    				/* ends if statement that asks for the numbers for a specific employee
    				after confirmation of correct employee number
    				*/
    				
    			} // closes the else for the case that employee num is a real employee
    		}
    		while (Val == 0);
    	}
    	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;
    }

  8. #8
    Registered User
    Join Date
    May 2009
    Posts
    242
    Just started on chap. 6, which is defining your own functions. I can already see what you guys mean (I think?):

    Basically, if (as in the above code) it's too complicated to follow the brackets for various loops, then portions of them need to be broken down into functions that suddenly turn big blocks into single lines that just call your function and thus make everything pretty transparent.

    Am I understanding you guys correctly?

    As my own exercise, I think I'll try re-writing the above code using some functions.

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Aisthesis View Post
    As my own exercise, I think I'll try re-writing the above code using some functions.
    I would start by looking at the sections which look like this:

    Code:
    			cout << "\nEmployee " << Num << " state tax: ";
    						cin >> State;
    			// validate
    						while (cin.fail() || (State < 0) || (State > Gross))
    						{		
    							cin.clear();
    							cin.ignore(100, '\n');
    							cout << "Invalid input!\n";
    							if (State < 0)
    								cout << "State tax cannot be negative.\n";
    							if (State > Gross)
    								cout << "State tax cannot exceed gross wages.\n";
    							cout << "Employee " << Num << " state tax: ";
    							cin >> State;
    						}
    These blocks of code are all extremely similar...
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  10. #10
    Registered User
    Join Date
    Sep 2001
    Posts
    4,912
    I'll second the advice to write functions that do one thing and do it well. It makes it easier to debug, maintain, and reuse your code. Also, even though comments help document your code, it's a good idea to regularly ask yourself if it wouldn't be better to make the code more readable by itself. Too many comments are a sign that your code is poorly written.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Reusing code blocks for different variables
    By Queue in forum C Programming
    Replies: 16
    Last Post: 09-16-2006, 11:34 AM
  2. Linked List Part 2
    By Nish in forum C Programming
    Replies: 18
    Last Post: 03-09-2005, 05:05 PM
  3. Obfuscated Code Contest
    By Stack Overflow in forum Contests Board
    Replies: 51
    Last Post: 01-21-2005, 04:17 PM
  4. Updated sound engine code
    By VirtualAce in forum Game Programming
    Replies: 8
    Last Post: 11-18-2004, 12:38 PM
  5. Interface Question
    By smog890 in forum C Programming
    Replies: 11
    Last Post: 06-03-2002, 05:06 PM