L.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 logic errors exist. 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. L.3, which creates and manipulates an object of class Account (Figs. L.1L.2). Execution begins in main (lines 1230 of Fig. L.3). Line 14 creates an Account object with an initial balance of $50.00. Account's constructor (lines 1022 of Fig. L.2) accepts one argument, which specifies the Account's initial balance. Line 17 of Fig. L.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.
Figure L.1. Header file for the Account class.
1 // Fig. L.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 |
Figure L.2. Definition for the Account class.
(This item is displayed on pages 1366 - 1367 in the print version)
1 // Fig. L.2: Account.cpp 2 // Member-function definitions for class Account. 3 #include 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 |
Figure L.3. Test class for debugging.
1 // Fig. L.3: figL_03.cpp 2 // Create and manipulate Account objects. 3 #include 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 will use breakpoints and various debugger commands to examine the value of the variable withdrawalAmount declared in Fig. L.3.
1. |
Enabling the debugger. The debugger is enabled by default. If it is not enabled, you have to change the settings of the Solution Configurations combo box (Fig. L.4) in the toolbar. To do this, click the combo box's down arrow to access the Solution Configurations combo box, then select Debug. The toolbar will display Debug in the Solution Configurations combo box.
Figure L.4. Enabling the debugger. |
2. |
Inserting breakpoints in Visual Studio .NET. To insert a breakpoint in Visual Studio .NET, click inside the margin indicator bar (the gray margin at the left of the code window in Fig. L.5) next to the line of code at which you wish to break or right click that line of code and select Insert Breakpoint. You can set as many breakpoints as necessary. Set breakpoints at lines 21 and 25 of your code. A solid maroon circle appears in the margin indicator bar where you clicked, indicating that a breakpoint has been set (Fig. L.5). When the program runs, the debugger suspends execution at any line that contains a breakpoint. The program is said to be in break mode when the debugger pauses the program's execution. Breakpoints can be set before running a program, in break mode and while a program is running.
Figure L.5. Setting two breakpoints. |
3. |
Beginning the debugging process. After setting breakpoints in the code editor, select Build > Build Solution to compile the program, then select Debug > Start to begin the debugging process. During debugging of a C++ program, a Command Prompt window appears (Fig. L.6), allowing program interaction (input and output). The program pauses when execution reaches the breakpoint at line 21. At this point, the title bar of the IDE will display [break] (Fig. L.7), indicating that the IDE is in break mode.
Figure L.6. Inventory program running. Figure L.7. Title bar of the IDE displaying [break]. |
4. |
Examining program execution. Program execution suspends at the first breakpoint (line 21), and the IDE becomes the active window (Fig. L.8). The yellow arrow to the left of line 21 indicates that this line contains the next statement to execute. [Note: We have added the yellow highlighting to these images. Your code will not contain this highlighting.]
Figure L.8. Program execution suspended at the first breakpoint. |
5. |
Using the Continue command to resume execution. To resume execution, select Debug > Continue. The Continue command will execute any statements between the next executable statement and the next breakpoint or the end of main, whichever comes first. The program continues executing and pauses for input at line 22. Input 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 that the variable stores is displayed in a Quick Info box (Fig. L.9). In a sense, you are peeking inside the computer at the value of one of your variables. As you'll see, this can help you spot logic errors in your programs.
Figure L.9. Setting a breakpoint at line 29. (This item is displayed on page 1370 in the print version) |
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 (Fig. L.9). 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 will not be able to view the program's output before the console window closes.
|
|
|
7. |
Continuing program execution. Use the Debug > Continue command to execute line 25. The program displays the result of its calculation (Fig. L.10).
Figure L.10. 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 maroon circle (Fig. L.11). Disabling rather than removing a breakpoint allows you to re-enable the breakpoint (by clicking inside the hollow circle) in a program. This also can be done by right clicking the line marked by the hollow maroon circle (or the maroon circle itself) and selecting Enable Breakpoint.
Figure L.11. 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 Remove Breakpoint. You also can remove a breakpoint by clicking the maroon circle 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.