3.5.9. Loops And The Debugger

Time: 00:11:50 | Download: Large Small | Streaming
Review

Just as manually instrumenting code helped us understand and debug statements, it can also help us understand and debug loops. Manually instrumenting loops has the dual disadvantages of requiring us to insert output statements when exploring a program's behavior and removing them when we are finished. Instrumentation still works with loops that primarily perform some calculation, like the while-loop in the gcd example. However, when the loop produces output during each iteration, the loop and instrumentation outputs are intermixed, making it difficult to read and understand either output. Worse still is the case where the output's formatting is a significant part of the solution (as with multtab). These situations are where the debugger demonstrates its value.

We'll use multtab, a program written previously in this chapter, to demonstrate some new debugger features. There are several reasons for choosing multtab.

The following screen captures show which controls to use but cannot show the debugger's full dynamic behavior. Watch the accompanying video to see better how the debugger operates.

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
	for (int i = 1; i <= 12; i++)
	{
		for (int j = 1; j <= 12; j++)
			cout << setw(5) << i * j;
		cout << endl;
	}

	return 0;
}
Demonstrating the debugger with multtab.cpp. You'll learn more about using the debugger and remember it better by following the example. Begin by ensuring that multtab is loaded, compiled, and set as the startup project.
A screen capture showing the popup menu displayed in response to right-clicking on the outer for-loop. The mouse pointer hovers over the "Run To Cursor" menu item.
The "Run To Cursor" operation. Position the mouse pointer on the line where debugging begins. In this example, place the cursor on line 7, the outer loop that drives the program through the rows. Right-click and select "Run To Cursor." The program begins running but pauses at the beginning of line 7.
The program pauses before the for-loop runs. The mouse pointer hovers over the loop control variable, <kbd>i</kbd>, and the debugger displays -858993460. Before the for-loop saves a value in <kbd>i</kbd>, it contains a random value.
Examining variable contents. Just as when we used a breakpoint to pause the program, we can still mouse over a variable to see the current value. Hovering the mouse pointer over variable i, the loop control variable of the outer loop, it seems to have a very negative value. That's because i hasn't been initialized yet, so it contains a random value. But hovering the mouse pointer over variable j doesn't display any output because j is out of scope and so isn't defined yet.
Right-clicking on variable i displays the popup window again. Select the 'Add Watch' menu item.
Watching variables. Right-click on or just behind the variable, and select "Add Watch."
 The 'Watch' window at the bottom of Studio has a row for every variable the programmer is watching. The debugger updates the displayed value whenever it changes during the debug session.
The "Watch" window. A "Watch" window opens at the bottom and an entry for variable i is visible. The entry is currently very negative, indicating that the variable is uninitialized. The debugger displays the current value stored in i whenever the program updates the value.
Right-click on variable j in the inner for-loop, and select "Add Watch" menu item.
Watch a second variable. Add a watch for variable j following the steps above.
A row for j is added to the "Watch" window. A red circle with a large X in it and the statement "identifier <kbd>j</kbd> is undefined" announce that j is still out of scope.
Updating the watch window. Adding the variable j to the watch list makes it clear that j is undefined. You can add watches for any variable or expression whose value you want to track – not just the loop control variables. You can also add a variable or expression directly into the watch window by entering its name or the expression in the field labeled "Add item to watch."
The single-step button is one of the most useful debugger controls. It is a button near the top of Visual Studio identified with a box with an arrow pointing into it. You can also single-step through a program by pressing control-F11.
The single-step button. The main control used for this debugging session is the context single-step button. This button implements one of the most useful debugger operations - the ability to execute and observe the program one statement at a time.
The debugger executes one statement each time a user presses the single-step or control-F11 button. The single-step operation runs the statement indicated by a yellow arrow on the left edge of the editor window. Whenever a statement changes the value saved in a watched variable, the debugger updates the displayed value in the Watch window. Stepping the program updates <kbd>i</kbd> to 1 and moves the program into <kbd>j</kbd>'s scope.
Single-Stepping. Press the single-step button once and observe the changes in the Watch window: The program initializes the value in variable i to 1, and j, although uninitialized, is now defined.
Stepping again updates j's value to 1.
Single-Stepping through nested loops. Pressing the single-step button again initializes both loop control variables. The arrow at the far left of line 10 indicates the running statement.
Pressing the single-step button or control-F11 cycles through the inner loop and causes j's value to count up to 12.
Stepping through the inner loop. Press the single-step button several times and watch the arrow on the left. The inner loop continues to run, producing a line of output on the console. Continue pressing the single-step button until j reaches a value of 12.
When j reaches 13, the inner loop ends. But the outer loop continues to run, advancing i to 2.
Ending the inner loop. Beginning with the arrow on line 9. slowly press the single-step button until the arrow moves to line 12. Notice that j advances to 13, ending the inner loop, and increases i to 2.
Stepping again causes the program to enter the inner loop, resetting j to 1.
The second iteration of the outer loop. Continue pressing the single-step button, moving the arrow to line 7, and updating the value saved in i to 2. The outer begins its next iteration, marked by a new line in the console window. If you continue pressing the step button, you can watch each entry print in the multiplication window. You can see the lines grow one product at a time, and you can see each line begin when the inner loop finishes.
There are three ways to stop the debugging session: First, you can continue stepping through the program until it ends. But, if you want to end sooner, you can press the stop button (decorated with a large red square), or you can press the Step Out button (a box with an arrow pointing out).
Ending the debug session. You can continue pressing the single-step button until the program finishes. However, if you would like to stop debugging, you can:
  1. Press "Continue"
  2. Press "Stop"
  3. Press "Step Out"
 When you no longer wish to observe a variable, right-click it in the watch window and select Delete Watch.

If you are watching multiple variables and want to remove all of them quickly, right-click on one and select Clear All from the popup window.
Clearing watches. You can add and remove watches whenever needed. If you no longer want to watch an item in the watch window, right-click it and select "Delete Watch," or select it and press the "Delete" key on the keyboard. You can also right-click anywhere in the watch window and select "Clear All" to remove all watches.