G. Using the Visual Studio Debugger

Objectives

In this appendix you’ll learn:

Image  To set breakpoints to debug programs.

Image  To run a program through the debugger.

Image  To set, disable and remove a breakpoint.

Image  To use the Continue command to continue execution.

Image  To use the Locals window to view and modify the values of variables.

Image  To use the Watch window to evaluate expressions.

Image  To use the Step Into, Step Out and Step Over commands to control execution.

Image  To use the Autos window to view variables that are used in the surrounding statements.

And so shall I catch the fly.

William Shakespeare

We are built to make mistakes, coded for error.

Lewis Thomas

What we anticipate seldom occurs; what we least expect generally happens.

Benjamin Disraeli

He can run but he can’t hide.

Joe Louis

It is one thing to show a man that he is in error, and another to put him in possession of truth.

John Locke

Outline

G.1 Introduction

In Chapter 2, you learned that there are two types of errors—compilation errors and logic errors—and you learned how to eliminate compilation errors from your code. Logic errors (also called bugs) do not prevent a program from compiling successfully, but can cause the program to produce erroneous results when it runs. Most C++ compiler vendors provide software called a debugger, which allows you to monitor the execution of your programs to locate and remove logic errors. The debugger will be one of your most important program development tools. This appendix demonstrates key features of the Visual Studio debugger. The features shown here work the same way in both Visual Studio 2005 and Visual Studio 2008. Appendix H discusses the features and capabilities of the GNU C++ debugger. Our C++ Resource Center (www.deitel.com/cplusplus/) provides links to tutorials that can help you familiarize yourself with the debuggers provided with various other development tools.

G.2 Breakpoints and the Continue Command

We begin our study of the debugger by investigating breakpoints, which are markers that can be set at any executable line of code. When program execution reaches a breakpoint, execution pauses, allowing you to examine the values of variables to help determine whether a logic error exists. For example, you can examine the value of a variable that stores the result of a calculation to determine whether the calculation was performed correctly. Note that attempting to set a breakpoint at a line of code that is not executable (such as a comment) will actually set the breakpoint at the next executable line of code in that function.

To illustrate the features of the debugger, we use the program listed in Fig. G.3, which creates and manipulates an object of class Account (Figs. G.1G.2). Execution begins in main (lines 12–30 of Fig. G.3). Line 14 creates an Account object with an initial balance of $50.00. Account’s constructor (lines 10–22 of Fig. G.2) accepts one argument, which specifies the Account’s initial balance. Line 17 of Fig. G.3 outputs the initial account balance using Account member function getBalance. Line 19 declares a local variable withdrawalAmount, which stores a withdrawal amount read from the user. Line 21 prompts the user for the withdrawal amount, and line 22 inputs the amount into withdrawalAmount. Line 25 subtracts the withdrawal from the Account’s balance using its debit member function. Finally, line 28 displays the new balance.

Fig. G.1 Header file for the Account class.

 1   // Fig. G.1: Account.h
 2   // Definition of Account class.
 3
 4   class Account
 5   {
 6   public:
 7      Account( int ); // constructor initializes balance
 8      void credit( int ); // add an amount to the account balance
 9      void debit( int ); // subtract an amount from the account balance
10      int getBalance(); // return the account balance
11   private:
12      int balance; // data member that stores the balance
13   }; // end class Account

Fig. G.2 Definition for the Account class.

 1   // Fig. G.2: Account.cpp
 2   // Member-function definitions for class Account.
 3   #include <iostream>
 4   using std::cout;
 5   using std::endl;
 6
 7   #include "Account.h" // include definition of class Account
 8
 9   // Account constructor initializes data member balance
10   Account::Account( int initialBalance )
11   {
12      balance = 0; // assume that the balance begins at 0
13
14      // if initialBalance is greater than 0, set this value as the
15      // balance of the account; otherwise, balance remains 0
16      if ( initialBalance > 0 )
17         balance = initialBalance;
18
19      // if initialBalance is negative, print error message
20      if ( initialBalance < 0 )
21         cout << "Error: Initial balance cannot be negative. " << endl;
22   } // end Account constructor
23
24   // credit (add) an amount to the account balance
25   void Account::credit( int amount )
26   {
27      balance = balance + amount; // add amount to balance
28   } // end function credit
29
30   // debit (subtract) an amount from the account balance
31   void Account::debit( int amount )
32   {
33      if ( amount <= balance ) // debit amount does not exceed balance
34         balance = balance - amount;
35

36      else // debit amount exceeds balance
37         cout << "Debit amount exceeded account balance. " << endl;
38   } // end function debit
39
40   // return the account balance
41   int Account::getBalance()
42   {
43      return balance; // gives the value of balance to the calling function
44   } // end function getBalance

Fig. G.3 Test class for debugging.

 1   // Fig. G.3: figg_03.cpp
 2   // Create and manipulate Account objects.
 3   #include <iostream>
 4   using std::cin;
 5   using std::cout;
 6   using std::endl;
 7
 8   // include definition of class Account from Account.h
 9   #include "Account.h"
10
11   // function main begins program execution
12   int main()
13   {
14      Account account1( 50 ); // create Account object
15
16      // display initial balance of each object
17      cout << "account1 balance: $" << account1.getBalance() << endl;
18
19      int withdrawalAmount; // stores withdrawal amount read from user
20
21      cout << " Enter withdrawal amount for account1: "; // prompt
22      cin >> withdrawalAmount; // obtain user input
23      cout << " attempting to subtract " << withdrawalAmount
24         << " from account1 balance ";
25      account1.debit( withdrawalAmount ); // try to subtract from account1
26
27      // display balances
28      cout << "account1 balance: $" << account1.getBalance() << endl;
29      return 0; // indicate successful termination
30   } // end main

In the following steps, you’ll use breakpoints and various debugger commands to examine the value of the variable withdrawalAmount declared in Fig. G.3.

1.   Enabling the debugger. The debugger is normally enabled by default. If it is not enabled, you have to change the settings of the Solution Configurations combo box (Fig. G.4) in the toolbar. To do this, click the combo box’s down arrow, then select Debug.

Fig. G.4 Enabling the debugger.

Enabling the debugger.

2.   Inserting breakpoints in Visual Studio. To insert a breakpoint in Visual Studio, click inside the margin indicator bar (the gray margin at the left of the code window in Fig. G.5) next to the line of code at which you wish to break or right click that line of code and select Breakpoint > Insert Breakpoint. You can set as many breakpoints as necessary. Set breakpoints at lines 21 and 25 of your code. A red circle appears in the margin indicator bar where you clicked, indicating that a breakpoint has been set (Fig. G.5). When the program runs, the debugger pauses execution at any line that contains a breakpoint. The program is said to be in break mode when the debugger pauses the program. Breakpoints can be set before running a program, in break mode and while a program is running.

Fig. G.5 Setting two breakpoints.

Setting two breakpoints.

3.   Starting to debug. After setting breakpoints in the code editor, select Build > Build Solution to compile the program, then select Debug > Start Debugging to begin the debugging process. [Note: If you do not compile the program first, it will still be compiled when you select Debug > Start Debugging.] When you debug a console application, a Command Prompt window appears (Fig. G.6) in which you can specify program input and view program output. The debugger enters break mode when execution reaches the breakpoint at line 21.

Fig. G.6 Inventory program running.

Inventory program running.

4.   Examining program execution. Upon entering break mode at the first breakpoint (line 21), the IDE becomes the active window (Fig. G.7). The yellow arrow to the left of line 21 indicates that this line contains the next statement to execute.

Fig. G.7 Program execution suspended at the first breakpoint.

Program execution suspended at the first breakpoint.

5.   Using the Continue command to resume execution. To resume execution, select Debug > Continue. The Continue command resumes program execution until the next breakpoint or the end of main is encountered, whichever comes first. The program continues executing and pauses for input at line 22. Enter 13 as the withdrawal amount. The program executes until it stops at the next breakpoint (line 25). Notice that when you place your mouse pointer over the variable name withdrawalAmount, the value stored in the variable is displayed in a Quick Info box (Fig. G.8). As you’ll see, this can help you spot logic errors in your programs.

Fig. G.8 Quick Info box showing the value of a variable.

Quick Info box showing the value of a variable.

6.   Setting a breakpoint at the return statement. Set a breakpoint at line 29 in the source code by clicking in the margin indicator bar to the left of line 29. This will prevent the program from closing immediately after displaying its result. When there are no more breakpoints at which to suspend execution, the program will execute to completion and the Command Prompt window will close. If you do not set this breakpoint, you won’t be able to view the program’s output before the console window closes.

7.   Continuing program execution. Use the Debug > Continue command to execute the code up to the next breakpoint. The program displays the result of its calculation (Fig. G.9).

Fig. G.9 Program output.

Program output.

8.   Disabling a breakpoint. To disable a breakpoint, right click a line of code on which a breakpoint has been set (or the breakpoint itself) and select Disable Breakpoint. The disabled breakpoint is indicated by a hollow circle (Fig. G.10). Disabling rather than removing a breakpoint allows you to reenable the break-point later by clicking the hollow circle or by right-clicking the hollow circle and selecting Enable Breakpoint.

Fig. G.10 Disabled breakpoint.

Disabled breakpoint.

9.   Removing a breakpoint. To remove a breakpoint that you no longer need, right click a line of code on which a breakpoint has been set and select Breakpoint > Delete Breakpoint. You also can remove a breakpoint by clicking the breakpoint in the margin indicator bar.

10.   Finishing program execution. Select Debug > Continue to execute the program to completion.

In this section, you learned how to enable the debugger and set breakpoints so that you can examine the results of code while a program is running. You also learned how to continue execution after a program suspends execution at a breakpoint and how to disable and remove breakpoints.

G.3 Locals and Watch Windows

In the preceding section, you learned that the Quick Info feature allows you to examine a variable’s value. In this section, you’ll learn to use the Locals window to assign new values to variables while your program is running. You’ll also use the Watch window to examine the value of more complex expressions.

1.   Inserting breakpoints. Clear the existing breakpoints. Then, set a breakpoint at line 25 in the source code by clicking in the margin indicator bar to the left of line 25 (Fig. G.11). Set another breakpoint at line 28 by clicking in the margin indicator bar to the left of line 28.

Fig. G.11 Setting breakpoints at lines 25 and 28.

Setting breakpoints at lines 25 and 28.

2.   Starting debugging. Select Debug > Start. Type 13 at the Enter withdrawal amount for account1: prompt and press Enter so that your program reads the value you just entered. The program executes until the breakpoint at line 25.

3.   Suspending program execution. The debugger enters break mode at line 25 (Fig. G.12). At this point, line 22 has input the withdrawalAmount that you entered (13), lines 23–24 have output that the program will attempt to withdraw money and line 25 is the next statement that will execute.

Fig. G.12 Program execution suspended when debugger reaches the breakpoint at line 25.

Program execution suspended when debugger reaches the breakpoint at line 25.
Program execution suspended when debugger reaches the breakpoint at line 25.

4.   Examining data. In break mode, you can explore the values of your local variables using the debugger’s Locals window. To view the Locals window, select Debug > Windows > Locals. Figure G.13 shows the values for main’s local variables account1 and withdrawalAmount (13).

Fig. G.13 Examining variable withdrawalAmount.

Examining variable withdrawalAmount.

5.   Evaluating arithmetic and boolean expressions. You can evaluate arithmetic and boolean expressions using the Watch window. You can display up to four Watch windows. Select Debug > Windows > Watch > Watch 1. In the first row of the Name column, type (withdrawalAmount + 3) * 5, then press Enter. The value of this expression (80 in this case) is displayed in the Value column (Fig. G.14). In the next row of the Name column, type withdrawalAmount == 3, then press Enter. This expression determines whether the value of withdrawalAmount is 3. Expressions containing the == operator (or any other relational or equality operator) are treated as bool expressions. The value of the expression in this case is false (Fig. G.14), because withdrawalAmount currently contains 13, not 3.

Fig. G.14 Examining the values of expressions.

Examining the values of expressions.

6.   Resuming execution. Select Debug > Continue to resume execution. Line 25 debits the account by the withdrawal amount, and the debugger reenters break mode at line 28. Select Debug > Windows > Locals or click the Locals tab at the bottom of Visual Studio to redisplay the Locals window. The updated balance value in account1 is now displayed in red (Fig. G.15) to indicate that it has been modified since the last breakpoint. Click the plus box to the left of account1 in the Name column of the Locals window. This allows you to view each of account1’s data member values individually—this is particularly useful for objects that have several data members.

Fig. G.15 Displaying the value of local variables.

Displaying the value of local variables.

7.   Modifying values. Based on the value input by the user (13), the account balance output by the program should be $37. However, you can use the Locals window to change the values of variables during the program’s execution. This can be valuable for experimenting with different values and for locating logic errors. In the Locals window, click the Value field in the balance row to select the value 37. Type 33, then press Enter. The debugger changes the value of balance and displays its new value in red (Fig. G.16).

Fig. G.16 Modifying the value of a variable.

Modifying the value of a variable.

8.   Setting a breakpoint at the return statement. Set a breakpoint at line 29 in the source code to prevent the program from closing immediately after displaying its result. If you do not set this breakpoint, you won’t be able to view the program’s output before the console window closes.

9.   Viewing the program result. Select Debug > Continue to continue program execution. Function main executes until the return statement in line 29 and displays the result. Notice that the result is $33 (Fig. G.17). This shows that Step 7 changed the value of balance from the calculated value (37) to 33.

Fig. G.17 Output displayed after modifying the account1 variable.

Output displayed after modifying the account1 variable.

10.   Stopping the debugging session. Select Debug > Stop Debugging. This will close the Command Prompt window. Remove all remaining breakpoints.

In this section, you learned how to use the debugger’s Watch and Locals windows to evaluate arithmetic and boolean expressions. You also learned how to modify the value of a variable during your program’s execution.

G.4 Controlling Execution Using the Step Into, Step Over, Step Out and Continue Commands

Sometimes executing a program line by line can help you verify that a function’s code executes correctly, and can help you find and fix logic errors. The commands you learn in this section allow you to execute a function line by line, execute all the statements of a function at once or execute only the remaining statements of a function (if you have already executed some statements within the function).

1.   Setting a breakpoint. Set a breakpoint at line 25 by clicking in the margin indicator bar to the left of the line.

2.   Starting the debugger. Select Debug > Start. Enter the value 13 at the Enter withdrawal amount for account1: prompt. Execution will halt when the program reaches the breakpoint at line 25.

3.   Using the Step Into command. The Step Into command executes the next statement in the program (the one that the yellow arrow points to in line 25 of Fig. G.18), then immediately halts. If that statement is a function call (as is the case here), control transfers into the called function. This enables you to execute each statement inside the function individually to confirm the function’s execution. Select Debug > Step Into to enter the debit function. Then, Select Debug > Step Into again so the yellow arrow is positioned at line 33, as shown in Fig. G.19.

Fig. G.18 Using the Step Into command to execute a statement.

Using the Step Into command to execute a statement.

Fig. G.19 Stepping into the debit function.

Stepping into the debit function.

4.   Using the Step Over command. Select Debug > Step Over to execute the current statement (line 33 in Fig. G.19) and transfer control to line 34 (Fig. G.20). The Step Over command behaves like the Step Into command when the next statement to execute does not contain a function call. You’ll see how the Step Over command differs from the Step Into command in Step 10.

Fig. G.20 Stepping over a statement in the debit function.

Stepping over a statement in the debit function.

5.   Using the Step Out command. Select Debug > Step Out to execute the remaining statements in the function and return control to the next executable statement (line 28 in Fig. G.3). Often, in lengthy functions, you’ll want to look at a few key lines of code, then continue debugging the caller’s code. The Step Out command enables you to continue program execution in the caller without having to step through the entire called function line by line.

6.   Setting a breakpoint. Set a breakpoint at the return statement of main at line 29 of Fig. G.3. You’ll make use of this breakpoint in the next step.

7.   Using the Continue command. Select Debug > Continue to execute until the next breakpoint is reached at line 29. Using the Continue command is useful when you wish to execute all the code up to the next breakpoint.

8.   Stopping the debugger. Select Debug > Stop Debugging to end the debugging session. This will close the Command Prompt window.

9.   Starting the debugger. Before we can demonstrate the next debugger feature, you must start the debugger again. Start it, as you did in Step 2, and enter 13 in response to the prompt. The debugger enters break mode at line 25.

10.   Using the Step Over command. Select Debug > Step Over (Fig. G.21) Recall that this command behaves like the Step Into command when the next statement to execute does not contain a function call. If the next statement to execute contains a function call, the called function executes in its entirety (without pausing execution at any statement inside the function), and the yellow arrow advances to the next executable line (after the function call) in the current function. In this case, the debugger executes line 25, located in main (Fig. G.3). Line 25 calls the debit function. The debugger then pauses execution at line 28, the next executable line in the current function, main.

Fig. G.21 Using the debugger’s Step Over command.

Using the debugger’s Step Over command.

11.   Stopping the debugger. Select Debug > Stop Debugging. This will close the Command Prompt window. Remove all remaining breakpoints.

In this section, you learned how to use the debugger’s Step Into command to debug functions called during your program’s execution. You saw how the Step Over command can be used to step over a function call. You used the Step Out command to continue execution until the end of the current function. You also learned that the Continue command continues execution until another breakpoint is found or the program exits.

G.5 Autos Window

The Autos window displays the variables used in the previous statement executed (including the return value of a function, if there is one) and the variables in the next statement to execute.

1.   Setting breakpoints. Set breakpoints at lines 14 and 22 in main by clicking in the margin indicator bar.

2.   Using the Autos window. Start the debugger by selecting Debug > Start. When the debugger enters break mode at line 14, open the Autos window (Fig. G.22) by selecting Debug > Windows > Autos. Since we are just beginning the program’s execution, the Autos window lists only the variables in the next statement that will execute—in this case, the account1 object, its value and its type. Viewing the values stored in an object lets you verify that your program is manipulating these variables correctly. Notice that account1 contains a large negative value. This value, which may be different each time the program executes, is account1’s uninitialized value. This unpredictable (and often undesirable) value demonstrates why it is important to initialize all C++ variables before they are used.

Fig. G.22 Autos window displaying the state of account1 object.

Autos window displaying the state of account1 object.

3.   Using the Step Over command. Select Debug > Step Over to execute line 14. The Autos window updates the value of account1’s balance data member (Fig. G.23) after it is initialized. The value of balance is displayed in red to indicate that it just changed.

Fig. G.23 Autos window displaying the state of account1 object after initialization.

Autos window displaying the state of account1 object after initialization.

4.   Continuing execution. Select Debug > Continue to execute the program until the second breakpoint at line 22. The Autos window displays uninitialized local variable withdrawalAmount (Fig. G.24), which has a large negative value.

Fig. G.24 Autos window displaying local variable withdrawalAmount.

Autos window displaying local variable withdrawalAmount.

5.   Entering data. Select Debug > Step Over to execute line 22. At the program’s input prompt, enter a value for the withdrawal amount. The Autos window updates the value of local variable withdrawalAmount with the value you entered (Fig. G.25).

Fig. G.25 Autos window displaying updated local variable withdrawalAmount.

Autos window displaying updated local variable withdrawalAmount.

6.   Stopping the debugger. Select Debug > Stop Debugging to end the debugging session. Remove all remaining breakpoints.

G.6 Wrap-Up

In this appendix, you learned how to insert, disable and remove breakpoints in the Visual Studio debugger. Breakpoints allow you to pause program execution so you can examine variable values. This capability will help you locate and fix logic errors in your programs. You saw how to use the Locals and Watch windows to examine the value of an expression and how to change the value of a variable. You also learned debugger commands Step Into, Step Over, Step Out and Continue that can be used to determine whether a function is executing correctly. Finally, you learned how to use the Autos window to examine variables used specifically in the previous and next commands.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset