Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Introduction: This laboratory provides an introduction to the creation, use and testing of functions within Dev C++ and extends the introduction to the Dev C++

Introduction:

This laboratory provides an introduction to the creation, use and testing of functions within Dev C++ and extends the introduction to the Dev C++ debugger in lab 4 by introducing debugger tools and concepts that specifically assist in the debugging of programs that include functions.

Part I: Using the debugger with functions

Start Dev-C++, open the lab8sample.cpp file and save it on the desktop. This is a C++ implementation of the Babylonian square root algorithm that you should remember from lab 1,2 and 4 except now the main algorithm has been moved to a function:

double babylonian(double N, double errormax)

This function called babylonian has two input arguments that are both double precision numbers - the number N of which we wish to find the square root.

- the maximum acceptable error in the found root errormax.

Both of these are passed into the function through call-by-value.It returns the square root of N as a double precision number through a return statement.

The function uses a do - while loop to ensure the algorithm loop repeats until a root is found that meets the error specification.

The program also includes the function sqr from the framework.

double sqr(double value)

This function has one input arguments that is a double precision number, value that we wish to square. It is passed into the function through call-by-value. It returns the square as a double precision number through a return statement.

On a review of the program, you will see that the main program has three variables (x, N, error) and one constant (MAXERROR) while the function babylonian has two variables as arguments (N and errormax) and also has three local variables (xnew, xold and fnerror).

As we did in lab 4, let us launch the program within the debugger/ To do this you need to:

Take Dev C++ out of full screen mode so that there is room for the console to be open and visible beside Dev C++.

Place a break-point in the program at an instruction so that it will stop and provide user control. We suggest using line 42, so the program stops before executing the first cout statement. To add a break point, left click on the line number in the editor window and you will see a check mark on a red circle appear (To remove a break point, just click again). You can add as many break points as you need to a program.

Start the program in the debugger by compiling it and then clicking the check-mark tool to launch the debugger.

When the console opens, move it beside Dev C++ so that both are visible.

As we did in lab 4, you can now use the "Next Line" button to move through the instructions and ensure your enter a value for N (enter any positive number) on the console when prompted. Use the new line button until the "x=babylonian(N, MAXERROR);" instruction is highlighted but do not execute this instruction as it is calls the function. When you reach an instruction with a function call, you have two choices:

Option 1: Choose "Next Line" and you will see the program moves to the next line of code in the main program with the square root for N calculated. Do this. Continue using "Next Line" to loop around the program including entry of a new value of N (Enter 9 this time) until you again reach the "x=babylonian(N, MAXERROR);" instruction.

Option 2: Choose the "Into Function" button now instead of "Next Line" and you will see that the program has stopped at the first instruction inside the babylonian function, allowing you to single step through the function line by line using "Next Line." Once the function completes, you can use "Next Line" to return to the main program.

This demonstrates a key tool for debugging functions. If a function has been well tested and is not a focus of the debugging task, "Next Line" can be used to use the function without having to get into the details of the function code. If instead, a function is the (potential) source of an error, you have the option to step into the function and test it along with the main program.

Part II: Watching variables - review of lab 4, now with functions

As you execute a program, it is a common requirement to be able to watch the values of variables. In C--, you will remember the list of variables that appeared on the left of the window. In Dev C++, a panel exists on the left side of the screen with the same purpose where you can see that value in variables that are being watched. The concept of a watch list exists, as Dev C++ has been designed to debug extremely large programs that many have hundreds or even thousands of variables and when debugging a program, you can choose the subset of variables that you want to monitor, so you can see only those relevant to the work you are doing.

To add a variable to the watch list, in your program, select the full name of each of the variables using the mouse (the declarations at the top of each function provide an easy place for all variable names) and right click, towards the bottom of the menu, you will see "Add to Watch." See below for an example. Select this option and add x, N, error, xold, xnew and fnerror to the watch list.

Note: There is also an "Add Watch" button in the debug tools;you can add to the watch list using this button, but it requires typing in the variable name so when you have long variable names, the right click menu can be more efficient. There will be more on this later.

When you rerun the program as in Part I, you will note that when you initially run the program, all of the variables that are in main are not initialized and contain random values while the variables from the functions are shown as "Not found in current context." This demonstrates that variables within a function are not shared with the main program.

You can now use "Next Line" and "Into Function" as you did in part I and see the variables change as the algorithm progresses through the calculations. Step through the program, including using the "Into Function" for one value of N. Within the function, N is modified on the very last line purely to demonstrate that when using call-by-value, when you step back into the main program the value of N is still the number you entered and is NOT changed by the function.

Continue until you again reach the "x=babylonian(N, MAXERROR);" instruction again. Note that the variables xnew, xold and error contain the last errors from the previous run of the function. Next step into the function using "Into Function." Note that the value in most (likely all) of the variables change as these variables have nothing to do with the variables from the previous call to the function and are re-declared and not initialized yet. This shows how nothing is remembered from previous calls to a function.

Another way to watch the values in variables, if you wish to quickly check it as you are debugging without adding it to the watch list, is to hover the mouse over the name of a variable in the program and the current value will be displayed in a small box beside the mouse; see xnew in the image below:

Part III: Using the Continue button - review of lab 4, now with functions

Another way to move quickly over areas of code that are known to be good is the "Continue" button. Add a break point on the "x=babylonian(N, MAXERROR);" instruction. Remove the break-point from line 42. Now, when you run your program, it will run all the code up to the new break point before stopping . That includes prompting the user for a value of N, so start the program in the debugger and ensure you move the console window so you can see it and provide a value for N as requested.

You can now as before use the "Into Function" and "Next Line" buttons to watch the program operation. Click on "Into Function" to show the program calls the function and "Next Line" a couple of times so you can see that they work. Now click "Continue" and the program will now execute all instructions (without stopping) until it reaches the next break point which is back at the function call. Remember that once the function completes and the results are output, there is another request for a new value of N. Enter a value on the console window and you will see the program then stops again at the function call statement.

Part IV: The confusion of overlapping variable names between functions

Since all functions in a program have their own variable name space, it is perfectly valid for variables with the same name to exist with differing functions. Although a valid programming technique, it can lead to confusion when debugging the program. Start this step by changing the variable fnerror within the babylonian function to error;this is required in three different places.

We now have a variable called error in two different functions main and babylonian (Remember main is just a function that is only special in that the program starts there when you run it.). These two variables have nothing to do with each other in the same way that error and fnerror had nothing to do with each other.

Clear all of the watch variables by right clicking in the watch list sub-window on the left of Dev C++ and choose "clear all." Now select the variable error within the babylonian function and add it to the watch list. Ensure you put the break point back onto line 42 and now run the program in the debugger. Note that the variable error in the watch list has the "Not found in current context" note beside it. Keep stepping through the program (remember to enter a value for N when prompted) and ensure you choose "Into Function" when the babylonian function is called. Once in the function, you will see that the variable in the watch list updates properly as you step through the code.

You can repeat the above step, by clearing the watch list and now adding the variable error from the main program by highlighting it and using the right click menu. You will now see that it updates and only reflects the variable in the main function and not affected when the variable is modified in the function.

Note: This is an example of a case where choosing the variable using the right click method is advantageous over the "Add Watch" button as, if you use the button, it is unclear which variable error is added to the watch list. You may not get the one you wanted.

Part V: Creating your first function - testing as you go

Now we are going to create a new program and write our first function. Open the framework file ch4framework.cpp. You can find this on the G drive in the 1606 folder. Do a save-as and name the file lab8.cpp and save it to the desktop.

The roots of quadratic equation below can be found with the quadratic formula:

The b2-4ac term is called the discriminant and its value determines the type of roots that the equation will have:

if it is 0, the equation has a repeated root at -b/(2a)

if it is positive, the equation has two real roots

if it is negative, the equation has two complex conjugate pair roots.

In this step, you need to create a function that meets the following prototype specification:

int classifyQuad (double a, double b, double c);

where a,b,c are the coefficients of the quadratic and the returned value meets the following specification:

0 is returned if the discriminant is 0 (i.e. repeated roots) +1 is returned if the equation has two real roots.

-1 is returned if the equation has two complex roots.

Create a function that meets the above specification within the lab8.cpp file. A key aspect of the creation of a function is to test the function to ensure that it behaves as expected. This can be done by making a simple main program (called a test driver) that calls the function with differing inputs ensuring that it provides the desired result in all cases.

Create a main program that provides this testing. Note, this main program given everything you have learned about the debugger, can be created without the use of any cout or cin statements. You should also only need one variable in the main program to store the result returned by the function as you can use hard coded numbers when you call the function.

i.e. ftest = classifyQuad(2,4,6); /// calls function for a=2, b=4, c=6

One aspect of creating a test driver is finding test cases (values for the variables) that ensure that all cases are trialed; for this function, that means you need to determine values that cover each of the three cases. Consider the b2-4ac term and pick three different sets of a,b,c values that makes it 0, any positive number and any negative number.

Note: To prove your attendance at this lab, submit file "lab8.cpp" containing your program by the end of the lab period.

Part VI: Creating a second function - testing as we go

Now we will create a second function to assist in the calculation of the roots. Note that the roots of the equation match one of the following cases:

Two real roots

Repeated root

Two complex roots

You need to create a function that returns the value of the term that is common to both the two real root and two complex roots cases as the abs function will have no effect in the two real root case. Your function should meet the following prototype specification:

double discriminantRoot (double a, double b, double c);

Note that this function needs to have a method to find a square root. Although C++ provides two methods for this (pow(x,0.5) or sqrt(x)), for this lab, please make use of the babylonian function from part I. Copy this function from the lab8starter.cpp program (ensure you copy just the function and no part of the framework or main program) and place it in the lab8.cpp file. Ensure you call this function within discriminantRoot when you need to calculate the square root.

Note: Since Dev C++ compiles programs sequentially from the top of the file, all variables/functions must be declared before they are used. As a result, the declaration of the babylonian function has to come before it is used in another function.

Note that the in C++, the absolute value can be calculated using the C++ fabs function (floating point absolute value) that has the following prototype specification (per C++ library):

double fabs (double x);

Modify the main program to test this new discriminantRoot function using the test values you used previously to ensure that it returns the expected values for the relevant term. We suggest that you comment out the previous test code (so you can get it back later if needed).

Part VII: Bringing it all together

You can now complete the program to match the provided sample executable by using both of the functions you have created and the babylonian function through the addition of a sentinel loop to the program that prompts the user for values of a, b, c using a=0 to cause the program to exit.

Within the sentinel loop, call the classifyQuad function to calculate the type of roots so you can then print out the roots using the discriminantRoot function to calculate the relevant term as needed with the appropriate formatting depending on the types of roots. In this step, you should again comment out the previous test code (so you can get it back later if needed) and add the needed code to the main function. You should not need to modify any of the functions created in the previous steps.

Part VIII: Still have time?

Open the function practice file posted on the class web site and implement some of the other practice functions included in the file. Ensure that you create the function and a test driver main program along with the test cases to validate each of the functions.

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Students also viewed these Databases questions