Systematic and Structured Programming, Part 2
Step Six - Finishing the Job
Like step two for the main program where you solved the primary problem, step five is a very important part of the process since you solved all the smaller problems that support the overall solution. Like all of the steps, it should not have taken a long time, and like all the previous steps, if you did a good job in step five, this next (and final) step will be made that much easier. This last part of the programming process simply involves following the instructions you developed in step five and completing and testing the code that you generate.
If you are working through this with the web page, you should change your program file name from QuadProg_StepFive.c to QuadProg_StepSix.c now so that you don't overwrite your fifth step. You will be reminded again to make this change at the end of this web page. Note that the version numbers are not added to the file names in this text since you will be in charge of knowing when you update your files.
As in step five, your final iterative pass will be through the stub functions, developing and testing the program code as you progress. Once again, there is little or no need to look back at previous operations. Once you have implemented the code for all the functions, your program should work.
In most cases, there is no particular order to follow with implementing the functions, however if you have functions that conduct input and/or output operations, it is sometimes a good idea to write the I/O functions first so that as your other functions are developed, you can use your I/O functions to conduct interim tests on your program. For this very simple program, it will work fine to implement the functions in the order they are found.
Start here
printTitle
From the step five process, the printTitle looks like the following:
void printTitle()
{
// initialize function/variables
// none
// print title complete
// print title, with endline
// print underline, with two endlines
}
You will simply fill in the code as specified by your step five specifications
void printTitle()
{
// initialize function/variables
// none
// print title complete
// print title, with endline
// function: printString, printEndline
printString( "QUADRATIC ROOT CALCULATOR" );
printEndline();
// print underline, with two endlines
// function: printString, printEndlines
printString( "=========================" );
printEndlines( TWO_ENDLINES );
}
You will notice the TWO_ENDLINES constant being used in the printEndlines function. Rather than putting a literal in here, it is better where possible to put in constants. However, this means defining a constant in the program. Go back up to the top of the program, below the header files and above the prototypes, and place the following:
// global constants
const int TWO_ENDLINES = 2;
This will support program readability, and minimize "magic numbers" in your code. Compile after every line or two but definitely compile before going on to the next function
promptForCoefficient
Like the printTitle function, From the step five actions, the function in step three form looks like the following:
int promptForCoefficient( char coefLetter )
{
// initialize function/variables
// prompt user for coefficient
// function: printString, printCharacter
// get the input from the user
// function: promptForInteger
// return the user input to the calling function
return 0; // temporary stub return
}
You have only to fill in the code necessary to respond to your program instructions:
int promptForCoefficient( char coefLetter )
{
// initialize function/variables
// prompt user for coefficient
// function: printString, printCharacter
printString( "Enter Coefficient " );
printCharacter( promptLetter );
printString( COLON_SPACE );
// get the input from the user
// function: promptForInteger
userInput = promptForInteger( "" );
// return the user input to the calling function
return userInput;
}
Two things to note:
- This function uses another constant. This just means you need to go back up to the global constants area of the program and place const char COLON_SPACE[] = ": ";. This will create a small string with a colon and a space to be displayed here and in another location in the program
- Now that the correct return quantity has been placed, the // temporary stub return comment is no longer needed so it is removed.
Remember to compile after every line or two of code
calcDiscriminant
Like many well-modularized functions, the instructions and the code for this function are simple. Here are the step three comments for this function:
int calcDiscriminant( int cof_A, int cof_B, int cof_C )
{
// initialize function/variables
// calculate the discriminant
// return the discriminant
return 0; // temporary stub return
}
And here is the code for this function:
int calcDiscriminant( int cof_A, int cof_B, int cof_C )
{
// initialize function/variables
int disc;
// calculate the discriminant
disc = cof_B * cof_B - ( 4 * cof_A * cof_C );
// return the discriminant
return disc;
}
While this is a pretty easy program to write, development of very complicated programs can be this easy or nearly this easy if you have created an effective, modular solution before you started coding
Remember to compile before you move on.
calcDenominator
Here are the design statements for this function:
int calcDenominator( int cof_A )
{
// initialize function/variables
// calculate the denominator
// return the denominator
return 0; // temporary stub return
}
And here is the code:
int calcDenominator( int cof_A )
{
// initialize function/variables
int denominator;
// calculate the denominator
denominator = 2 * cof_A;
// return the denominator
return denominator;
}
Remember that you must compile after every line or two of written code to keep from piling up problems that will slow you down later.
calcRoot
Here are design steps for this function:
double calcRoot( int cof_B, int denom, double discSqrRoot )
{
// initialize function/variables
// calculate the numerator
// calculate the root
// return the root
return 0.0; // temporary stub return
}
And here is the code:
double calcRoot( int cof_B, int denom, double discSqrRoot )
{
// initialize function/variables
double numerator, rootSolution;
// calculate the numerator numerator = -cof_B + discSqrRoot;
// calculate the root
rootSolution = numerator / denom;
// return the root
return rootSolution;
}
displayInputValues
Here are the design statements for this function:
void displayInputValues( int coefA, int coefB, int coefC )
{
// initialize function/variables
// show data display
// display the leader text
// function: printEndline, printString
// display coefficent A with comma and space
// function: printString, printInteger
// display coefficient B with comma, space, and "and"
// function: printString, printInteger
// display coefficient C with comma
// function: printInteger, printCharacter
// display end line
// function: printEndline
}
And here is the code. Note that we found that we did not need the printEndline function for the display root number operation:
void displayInputValues( int coefA, int coefB, int coefC )
{
// initialize function/variables
// show data display
// display the leader text
// function: printEndline, printString
printEndline();
printString( &With coefficients of " );
// display coefficent A with comma and space
// function: printString, printInteger
printInteger( coefA );
printString( COMMA_SPACE );
// display coefficient B with comma, space, and "and"
// function: printString, printInteger
printInteger( coefB );
printString( ", and " );
// display coefficient C with comma
// function: printInteger, printCharacter
printInteger( coefC );
printCharacter( COMMA );
// display end line
// function: printEndline
printEndline();
}
This function needs a constant called COMMA. This is just a comma so you can add this to your list of constants up in the global constant area. And once again, keep compiling
displayRoot
Here are the design statements for this function:
void displayRoot( int rootNum, double rootSolution )
{
// initialize function/variables
// none
// show root display
// display the root number with leader
// function: printString, printInteger
// display colon with space
// function: printString
// display root value
// function: printDouble
// end the line
// function: printEndline
}
And here is the code. Note that we found that we did not need the printEndline function for the display root number operation:
void displayRoot( int rootNum, double rootSolution )
{
// initialize function/variables
// none
// show root display
// display the root number with leader
// function: printString, printInteger
printString( "Root Number " );
printInteger( rootNum );
// display colon with space
// function: printString
printString( COLON_SPACE );
// display root value
// function: printDouble
printDouble( rootVal, PRECISION );
// end the line
// function: printEndline
printEndline()
}
This function reuses COLON_SPACE but needs a new constant called PRECISION. This constant is set to two (up in the global constants area) so there are two digits printed to the right of the decimal. Again, using a self-documenting constant is far superior to putting in a magic number. And one more time, keep compiling
To see the step six process in action, watch this video; then develop your step six code with or without the video, as needed.
Wrapping Up Step Six (and the Program)
While it may seem miraculous, it is very likely that your program will compile and run the first time you try it, even if it is much more complicated and longer than the one used here as an example. Even if it doesn't run correctly, or seems to have some problems, the debugging process has been made incredibly simple since you should be able to identify any module that isn't working correctly
Okay, so there is one more thing to do. Try this again - practice writing this program two or three times. It will never be particularly difficult, but you will get faster and better at it if you practice a few times. And then go ahead: Bask in the Glory
Run the Program
One of the most powerful outcomes of using this six step programming process is that when you are done writing your program, you rarely have to go back
The program just completed should run the first time, for the following reasons:
- you solved the problem before you wrote the program; you even solved the small problems related to the modules before you wrote that code
- you wrote the overview of the program in a few simple statements before you went deeply into it (step one); you made sure the problem was solved before you moved on
- you took your original overview and, following your own simple instructions, created all of the solution as pseudocode statements (step two); again, you looked over your work and made sure that your statements would solve the problem
- you identified modules (i.e., functions) that would contribute toward parts of the program that needed to be conducted (step three); you made sure that the modules and components of the program would solve the problem before you went on, even if you didn't know exactly what would happen in each module
- You wrote the code for the main function knowing it would be fully correct because you knew that your design solved the problem (step four)
- you reused the first three steps to design the operations of each of your functions (step five)
- you finished the process by filling in some fairly simple code solutions to some fairly simple problems (step six), and because the modules were narrowly focused, they never really got too complicated
This is pretty much all there is to it. The key, as stated before, is to never solve big problems. Break the program into smaller quantities, and solve each item one at a time. No program will ever be too big to handle if you follow this process
Wrapping Up the Final Design Component
In order to conduct this part of the process, you must remember to save your QuadProg_StepFive.c file to QuadProg_StepSix.c before you make any changes. You want to keep your step five program exactly as it was so that if there are questions in the future about your overall strategy, you can go back and review the code.