Section 8d

Step Three - Locating, Identifying, and Designing Functions


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Systematic and Structured Programming, Part 2

Step Three - Locating functions and Creating Specifications

Once again, step two was not difficult. In fact, between writing steps one and two, you probably still don't have a whole 20 minutes invested in this process. That's just one of the benefits here.

Once again (again), you will also find that step three is just an expansion of step two, although you will be taking some new actions here. Mostly however, you will just be filling in areas that are guided by what you wrote in your previous steps.

If you are working through this with the web page, you should create a new QuadProg_StepThree.c file and copy your QuadProg_StepTwo.c code into it so that you don't overwrite your second step. You will be reminded again to make this change at the end of this web page.

Now, you must work your way through the program from top to bottom following the iterative refinement process. This time, you will be identifying the need for, and the use of, functions in your program.

Start here

Initialize the program

// initialize program

// initialize variables

// show title

There is still very little to do here, but we will create a function to conduct the print title operation

You have specified that you want to print a title. This is not terribly complicated but it's a place to start

Consider the requirements you have specified related to printing the title:

Taking a minute or two to consider this information will help you figure out how to design the necessary function

So now, you create a specification for your function up above the main function in the // function prototypes area that looks like the following:

/*
Name: displayTitle
Process: displays the program title on the monitor
Function Input/Parameters: none
Function Output/Parameters: none
Function Output/Returned: none
Device Input/Keyboard: none
Device Output/Monitor: title displayed
Dependencies: Console IO Utilities tools
*/

This is also the point where you can create the function prototype and the stub function for later use. Creating the prototype will tell the compiler that the function exists prior to its use in the main function, and creating the stub function will support correct compiling, and will later be there when it comes time for you to conduct steps five and six.

If you recall from Chapter 0, the whole structure of a program source file is as follows:

// headers or include files
// global constants
// function prototypes
// the main program
// suppporting function implementations

The function prototype is placed immediately under the specification block and in the function prototypes area, and the stub function is placed under the supporting function implementations as shown here

// headers or include files

// global constants

// function prototypes

/*
Name: displayTitle
Process: displays the program title on the monitor
Function Input/Parameters: none
Function Output/Parameters: none
Function Output/Returned: none
Device Input/Keyboard: none
Device Output/Monitor: title displayed
Dependencies: Console IO Utilities tools
*/
void displayTitle();


// the main program

// suppporting function implementations

void displayTitle()
{

}

Note that the displayTitle prototype has a semicolon after it, and the stub function down below has curly braces (and no semicolon).

Make sure you don't have any errors after writing this code. Next up is the input operation to get the coefficients.

Get the coefficients from the user

// get coefficients from user

// get coefficient A

// get coefficient B

// get coefficient C

You have specified that you want to get the three coefficients from the user. This will certainly require one or more functions in order to keep the program modular (and to keep your main function from getting more complicated)

Consider the requirements you have specified related to getting the coefficients from the user:

Taking a minute or two to consider this information will help you figure out how to design the necessary function

So now, you create a specification and a prototype up in the function prototypes area alphabetically after displayTitle that looks like the following:

/*
Name: promptForCoefficient
Process: prompt user for appropriate coefficient,
get coefficient, return coefficient
Function Input/Parameters: coefficient letter (char)
Function Output/Parameters: none
Function Output/Returned: acquired coefficient (int)
Device Input/Keyboard: user input
Device Output/Monitor: prompt displayed
Dependencies: Console IO Class tools
*/
int promptForCoefficient( char coefLetter );

And in the supporting function implementations area, alphabetically after displayTitle

int promptForCoefficient( char coefLetter )
{

return 0; // temporary stub return
}

Two notes about this:

Again, make sure there are no errors or warnings as you compile during and after writing these lines.

Now you will write the name of the function in your program as shown. You can see how this would look right at this point here. Notice the re-use of the function; this is already evidence of good quality programming.

// get coefficients from user

// get coefficient A
// function: promptForCoefficient

// get coefficient B
// function: promptForCoefficient

// get coefficient C
// function: promptForCoefficient

Process the quadratic roots

// Process the quadratic roots

// calculate the discriminant

// calculate the square root of the discriminant

// calculate the denominator

// Calculate the roots

// calculate root one

// calculate root two

There are several actions to be taken here, but that just provides an opportunity to practice with simple functions

For the first operation ("calculate the discriminant"), you have specified that you want to calculate the discriminant (i.e., the calculations under the radical). As before, this will require a function in order to keep the program modular

Consider the requirements you have specified related to calculating the discriminant for every combination of coefficients the user provides:

Taking a minute or two to consider this information will help you figure out how to design the necessary function

So now, you create a specification and the stub for your function up in the function prototypes area alphabetically before the getCoefficient function that looks like the following:

/*
Name: calcDiscriminant
Process: calculate discriminant with three coefficients
and return
Function Input/Parameters: three coefficients (int)
Function Output/Parameters: none
Function Output/Returned: calculated discriminant (int)
Device Input: none
Device Output: none
Dependencies: none
*/
int calcDiscriminant( int cofA, int cofB, int cofC );

And again, place the stub function down below alphabetically before the getCoefficient function, as shown here

int calcDiscriminant( int cofA, int cofB, int cofC )
{

return 0; // temporary stub return
}

For the next operation ("calculate the square root of the discriminant"), the square root of the discriminant must be found. You could write a square root calculation function, but for purposes of this activity, it is much easier to use the library function sqrt. So, since you will be using the math.h library function, you will not have to do an analysis of the problem, and you will not have to create a function. The function: sqrt will be placed under this step two statement.

For the next operation ("calculate the denominator"), you have specified that you want to calculate the denominator of the quadratic equation. As before, this will require a function in order to keep the program modular

Consider the requirements you have specified related to calculating the denominator for every coefficient A the user provides:

Taking a minute or two to consider this information will help you figure out how to design the necessary function

So now, you create a specification for your function up in the function prototype area alphabetically prior to calcDiscriminant that looks like the following:

/*
Name: calcDenominator
Process: calculate denominator with coefficient A
and return
Function Input/Parameters: coefficient A (int)
Function Output/Parameters: none
Function Output/Returned: calculated denominator (int)
Device Input: none
Device Output: none
Dependencies: none
*/
int calcDenominator( int coef_A );

And the stub function in the supporting function implementations down below:

int calcDenominator( int coef_A )
{

return 0; // temporary stub return
}

Finally, for the last root processing operations ("calculate root one" and "calculate root two"), you have specified that you want to calculate the two roots of the equation using the solution components you have already generated (i.e., the square root of the discriminant and the denominator). As usual, this will require a function in order to keep the program modular.

Consider the requirements you have specified related to calculating the root for every set of data the user provides:

Taking a minute or two to consider this information will help you figure out how to design the necessary function

So now, you create a specification for your function up in the function prototypes area alphabetically after the calcDiscriminant function that looks like the following:

/*
Name: calcRoot
Process: calculate single root solution with previously
processed equation components, and return
Function Input/Parameters: coefficient B and the denominator (int),
and the square root
of the discriminant (double)
Function Output/Parameters: none
Function Output/Returned: calculated single root (double)
Device Input: none
Device Output: none
Dependencies: none
*/
double calcRoot( int coef_B, int denominator, double discSqrt );

And once again, placing the stub function down in the supporting function implementations area:

double calcRoot( int coef_B, int denominator, double discSqrt )
{

return 0; // temporary stub return
}

Now that you have specified (i.e., created the specifications for) the functions you wish to use, you may fill in the appropriate areas in the main part of your program, as shown here

// Process the quadratic roots

// calculate the discriminant
// function: calcDiscriminant

// calculate the square root of the discriminant
// function: sqrt

// calculate the denominator
// function: calcDenominator

// calculate the roots

// calculate root one
// function: calcRoot

// calculate root two
// function: calcRoot

Now that the processing has been completed, you can move on to the display part of the program.

Display the roots

// display roots

// display user input values

// display root one

// display root two

The actions are also pretty easy for the output display, but you can again take advantage of the characteristics of functions if you will take the time to think it through. Consider the "what's in common/what's different" questions for these two more processes

There are going to be a variety of functions needed to display the user input. This is a reason to abstract the operation (i.e., hide the details) and place the various print statements in a function.

Consider the requirements you have specified related to displaying the user input:

Taking a minute or two to consider this information will help you figure out how to design the necessary function

So now, you create a specification for your function up in the function prototype area alphabetically after the calcDiscriminant function that looks like the following:

/*
Name: displayUserInput
Process: display user input values prior to displaying roots
Function Input/Parameters: three user input values (int)
Function Output/Parameters: none
Function Output/Returned: none
Device Input: none
Device Output/Monitor: user input values
Dependencies: Console IO Utility tools
*/
void displayUserInput( int coefA, int coefB, int coefC );

Place the stub function down below, alphabetically

void displayUserInput( int coefA, int coefB, int coefC )
{

}

There will also be more operations to display the roots. However, one function can be used for displaying each root individually.

Consider the requirements you have specified related to displaying one of the roots for every set of data the user provides:

Taking a minute or two to consider this information will help you figure out how to design the necessary function

So now, you create a specification for this function up in the function prototype area alphabetically after the calcDiscriminant function (but before the displayUserInput function) that looks like the following:

/*
Name: displayRoot
Process: display root number and root solution
Function Input/Parameters: root number (1 or 2) (int),
and root solution (double)
Function Output/Parameters: none
Function Output/Returned: none
Device Input: none
Device Output/Monitor: root number and root solution
Dependencies: Console IO Utility tools
*/
void displayRoot( int rootNum, double rootValue );

And once again, the stub function goes down in the supporting function implementation area

void displayRoot( int rootNum, double rootValue )
{

}

Note in this case, like the displayTitle, these functions display an output to the device (i.e., the monitor) but do not return any processed data back to the calling function (i.e., the main function). Thus, there is no return statement for either displayUserInput or displayRoot.

With the display function specified, you can place it in the appropriate place in your code

// display roots

// display user input values
// function: displayUserInput

// display root one
// function: displayRoot

// display root two
// function: displayRoot

End the program

// end program

// display program end

You will actually need two more functions to show the end of the program, but like the square root function, these have also been written for you. You will simply be using the printString and printEndline functions for this part.

// end program

// display program end
// function: printString, printEndline

Wrapping Up Specifications and Stub Functions

The stub creation part of step three is mostly a management process so that your program will continue to compile correctly even as you move into step four. It is appropriate to do it in this step because this is where you are specifying and locating the functions you will use.

Having said that, creating these code components is as easy as following the instructions you gave yourself. It never needs to be any more difficult than this

Some more notes:

This step -- in this page -- may seem long but it is mostly because code is typed and re-typed quite a bit. The actual step three takes no more time than the typing you need to do. Again, much of what you did in this step was just following instructions from the previous steps and much of what you will do in the succeeding steps will be following the instructions you created here.


To see the step three process in action, watch this video; then develop your step three code with or without the video as needed.