Search

1.11a — Debugging your program (watching variables and the call stack)

In the previous lesson on stepping and breakpoints, you learned how to use the debugger to watch the path of execution through your program. However, stepping through a program is only half of what makes the debugger useful. The debugger also lets you examine the value of variables as you step through your code.

Our examples here will be using the Visual Studio Express debugger -- if you are using a different IDE/debugger, the commands may have slightly different names or be located in different locations.

Before proceeding: Make sure your program is set to use the debug build configuration.

Watching variables

Watching a variable is the process of inspecting the value of a variable while the program is executing in debug mode. Most debuggers provide several ways to do this. Let’s take a look at a sample program:

This is a pretty straightforward sample program -- it prints the numbers 1, 2, 4, and 8.

First, use the “Run to cursor” command to debug to the first std::cout << x << " "; line:

At this point, the variable x has already been created and initialized with the value 1, so when we examine the value of x, we should expect to see the value 1.

The easiest way to examine the value of a simple variable like x is to hover your mouse over the variable x. Most modern debuggers support this method of inspecting simple variables, and it is the most straightforward way to do so.

Note that you can hover over any variable x, not just the one on the current line:

If you’re using Visual Studio, you can also use QuickWatch. Highlight the variable name x with your mouse, and then choose “QuickWatch” from the right-click menu.

This will pull up a subwindow containing the current value of the variable:

Go ahead and close QuickWatch if you opened it.

Now let’s watch this variable change as we step through the program. First, choose “Step over” twice, so the next line to be executed is the second std::cout << x << " "; line:

The variable x should now have value 2. Inspect it and make sure that it does!

The watch window

Using the mouse hover or QuickWatch methods to inspect variables is fine if you want to know the value of a variable at a particular point in time, but it’s not particularly well suited to watching the value of a variable change as you run the code because you continually have to rehover/reselect the variable.

In order to address this issue, all modern compilers provide another feature, called a watch window. The watch window is a window where you can add variables you would like to continually inspect, and these variables will be updated as you step through your program. The watch window may already be on your screen when you enter debug mode, but if it is not, you can bring it up through your IDEs window commands (these are typically found in the view or debug menus).

In Visual Studio 2005 Express, you can bring up a watch menu by going to Debug Menu->Windows->Watch->Watch 1 (note: you have to be in debug mode, so step into your program first).

You should now see this:

There is nothing in this window because we have not set any watches yet. There are typically two different ways to set watches:

1) Type in the name of the variable you would like to watch in the “Name” column of the watch window.
2) Highlight the variable you would like to watch, right click, and choose “Add Watch”.

Go ahead and add the variable “x” to your watch list. You should now see this:

Now chose the “Step over” command a few times and watch the value of your variable change!

Note that variables that go out of scope (e.g. variables declared in a function, when the function is not running) will stay in your watch window. If the variable returns to scope (e.g. the function is called again), the watch will pick it up and begin showing its value again.

Using watches is the best way to watch the value of a variable change over time as you step through your program.

The call stack window

Modern debuggers contain one more debugging information window that can be very useful in debugging your program, and that is the call stack window.

When your program calls a function, you already know that it bookmarks the current location, makes the function call, and then returns. How does it know where to return to? The answer is that it keeps track in the call stack.

The call stack is a list of all the active functions that have been called to get to the current point of execution. The call stack includes an entry for each function called, including what line was actively executing. Whenever a new function is called, that function is added to the top of the call stack. When the current function returns to the caller, it is removed from the top of the call stack, and control returns to the function just below it.

If you don’t see the call stack window, you will need to tell the IDE to show it. In Visual Studio 2005 Express, you can do that by going to Debug Menu->Windows->Call Stack (note: you have to be in debug mode, so step into your program first).

Let’s take a look at the call stack using a sample program:

Put a breakpoint in the CallC() function and then start debugging mode. The program will execute until it gets to the line you breakpointed.

Although you now know the program is executing CallC(), there are actually two calls to CallC() in this program (one in CallB(), and one in CallA()). Which function was responsible for calling CallC() this time? The Call stack will show us:

(Note that your line numbers may differ slightly)

The program started by calling main(). main() called CallA(), which called CallB(), which called CallC(). You can double-click on the various lines in the Call Stack window to see more information about the calling functions. Some IDEs take you directly to the function call. Visual Studio 2005 Express takes you to the next line after the function call. Go ahead and try this functionality out. When you are ready to resume stepping through your code, double-click the top line of the call stack window and you will return to your point of execution.

Continue running your program. Your breakpoint should be hit a second time when CallC() is called a second time (this time, from CallA()). You should see this reflected in the call stack:

Conclusion

Congratulations, you now know the basics of debugging your code! Using stepping, breakpoints, watches, and the call stack window, you now have the fundamentals to be able to debug almost any problem. Like many things, becoming good at using a debugger takes some practice and some trial and error. However, the larger your programs get, the more valuable you will find the debugger to be, so it is definitely worth your time investment!

1.12 -- Chapter 1 comprehensive quiz
Index
1.11 -- Debugging your program (stepping and breakpoints)

47 comments to 1.11a — Debugging your program (watching variables and the call stack)

  • Tang

    Alex, thank you very much. Your lessons are very interesting and very useful for me.

  • Simon

    Somehow when i’m debugging using the Step Into method (F11 in Visual Studio 2013) I sometimes I get a (seemingly) random long block of code until I click back on my cpp file. Any suggestions?

  • Mustho

    If one is not interested in debugging, he may not start programming. Debugging is what programming is all about!

  • Alpan

    I never saw an expression like "int x(1);"
    Is that correct syntax-wise?

    • Alex

      Yes, it’s correct.

      This does an implicit initialization of variable x. Initializing variables this way in C++ is more commonly seen with classes than fundamental types like integers, but there are good reasons to use it for the fundamental types too.

      • Chris H

        Is this considered as forward declaring variables? I remember reading this in a previous section.

        • Alex

          No. The statement defines (instantiates) a variable and initializes it with a value.

          The following two statements are nearly identical for fundamental types:

  • Aroma

    Alex ,is a great job you are doing here!, Thanks so much for this wonderful tutorials, am really enjoying programming by your courtesy. Thanks a million!

  • Aiden

    Hey Alex, The question I have isn’t related to this lesson, but i just thought of posting it. Anyway, i wrote this code

    #include "stdafx.h"
    #include <iostream>

    int add(int n, int b);

    int main(int x, int y, int n, int b)
    {
        using namespace std;

        cout << "Enter a number: ";

            cin >> x;
            cout << "Enter a number : ";
            cin >> y;
            cout << "Enter another: ";
                cin >> n;
                cout << "One more: ";
                    cin >> b;
                cout << x << " + " << y << " + " << b << " + " << n << " = " << x + y + b + n << endl;

        return 0;
    }

    int add(int n, int b)
    {

        using namespace std;

        cin >> n;
        cout << "Enter another: ";
        cin >> b;
        cout << "One more: ";

        cout << n << " + " << b << " = " << endl;

        return 0;
    }

    and when I run it, and I type in all  the number for it to add, it gets mixed up. Say i put in 5, 4, 4, 3 It would add 5, 4, 3, 4 which is fine, but i was just wondering what i was doing wrong? and after i put in every number, it says the program has stopped working, But when i click close program, it goes right back and says press any key to continue like normal.

  • Aiden

    Oops, now I see my problem with the adding, but I still wonder why does it say it stopped working?

    • Alex

      I think it’s crashing because you’ve declared your variables as parameters to main, which is confusing the compiler. Main should not have any parameters, and the variables should be declared locally.

      e.g. instead of:

      Do this:

  • 321123

    After first breakpoint when you want to make you program keep running until a breakpoint is hit again.
    Don’t use F11, you will step into the Ostream’s code.
    Just hit F5(Continue) and the program will run until it hit breakpoint again.

    Maybe the F5(continue) hotkey should be mentioned in this or the previous part of the guide when “Continue” is mentioned.
    It’s easy to confuse continue with F11(step in) that we used earlier.

  • Zak

    I never knew programming will be so easy until I came accros website …. Thanks a millions Alex

  • Bogche

    Thanks Alex you are one of the "GREATH TEACHERS" of the world.

  • huehuHUEHUE

    Behaviour in codeblocks is weird, the call stack gives a weird name to one of the functions "#1 0x40143d    _fu1___ZSt4cout() (C:\CBProjects\HelloWorld\main.cpp:10)"

    I was expecting it to say CallB() there.

    • Alex

      When the compiler compiles functions, it mangles the names of the functions (so it can do function overloading, a topic we’ll talk about later). Code::blocks may be showing you the mangled names.

  • I use Xcode for programming in C++ and what’s kinda strange is that you cannot enter debug mode directly for command line projects, almost all menu items below Debug stay disabled (you cannot click “step into” like in Visual Studio to start debugging, cause it’s disabled while you are not in debug mode yet). So what I do every single time I want to debug a Command Line project, is entering the debug mode by using breakpoints. So by adding a breakpoint at some row (e.g. before “int main()”, where the project starts), I can enter the debug mode from there by starting the project.

    So after starting the project, it stops at the breakpoint and I can use all debug tools from there:
    - the watch window
    - the steps (step in, over, out)
    - the call stack window
    - etc….

    Hopefully this helps anybody who’s using Xcode, who finds out that all debug menu items are disabled.
    Or if somebody has a better idea to start debug mode, let me know.

  • Sergio Ramos

    Ok, i missed something… what is this?

    int x(1);

    Function declaration passing an argument without any defanition? Does that just return 1 since there is no body to it, yet it is passing 1 into nothing? And what section was this convention introduced to declare "int x = 1;"?

    • Alex

      My bad. I moved this tutorial from later in the series, when I’d already introduced that concept. It’s the equivalent of int x = 1.

      I’ve updated the example.

      I discuss this form of initialization at the beginning of chapter 2 (you’re so close!).

  • AlexM

    Hi Alex, and first of all thanks for this site!

    Posible I`m wrong but I have to ask:  this code  I write  below gives me some error …

    ..cpp(13): error C2374: ‘x’: redefinition; multiple initialization.
    and so on in all the lines the x apears.
    Is this a problem for debuging?

    Thanks again!

    • Alex

      Yes, it’s a problem for debugging. Compiling your program is a prerequisite for debugging it. Consequently, you’ll need to fix up your program first.

  • Brian

    Alex, just wanted to say first off, great tutorials. After my 10 and 12 year old children finish learning how to type properly, I am putting them on to your web site to learn about programming. With that in mind, I’d like to make a simple suggestion regarding your instructions. Specifically with regards to the following line.

    ‘Now let’s watch this variable change as we step through the program. First, choose “Step over” twice, so the next line to be executed is the second std::cout << x << " "; line:’

    You might want to change it to:

    ‘Now let’s watch this variable change as we step through the program. First, close the Quick Watch window and choose “Step over” twice, so the next line to be executed is the second std::cout << x << " "; line:’

    My only reason is, I had thought the Quick Watch window could remain open and I could proceed by switching focus to the code and stepping through the program, but quickly realized I couldn’t. I’m looking forward to putting my kids unto your web site and I’d hate for them to get frustrated when reading and following your instructions using the IDE. (I’m new to IDEs as well.) I will be following your tutorial to the bitter end and appreciate all your hard work. Keep up the great work. (You should write a tutorial on how to write well written and superbly organized tutorials. :))

  • Brian

    One final note regarding your example with respect to Call Stacks. (Having written instructions with diagrams for others to follow as a System’s analyst, I know fixing it may not be worth the effort.) The code that you give for your example Test2 and the line numbers shown by the example image of the Call Stack window do not match. Doing exactly as you had written, I found that the first break-point added within the CallC function pauses the code is at line 6, and not line 9 as depicted by your example Call Stack Window image. (Picky I know, but I strive to keep all confusing aspects when demonstrating code to others to a minimum, thus reducing the number of trivial questions.)

    • Alex

      Thanks, I added a note that your line numbers may differ slightly, to let users know that this is not important to the example. I appreciate the feedback.

  • Nyap

    I keep getting "cannot open file: fileops.c" from codeblocks when I try doing anything with the debugger ;(
    can’t find anything online about it either ;(

    • Alex

      Unfortunately, this is beyond my knowledge. 🙁

    • Nyap

      if anybody else happens to have the same issue, I’ve found a solution (sort-of)
      put a breakpoint on the first line of all the cpp files and it sort of works but might behave weird every now and then
      I wouldn’t class it as "a good debugging solution" though, but it will be fine for small programs

  • Derek

    My Call Stack window has this listed:
       Calling.exe!CallC() Line 8
       Calling.exe!CallB() Line 16
       Calling.exe!CallA() Line 21
       Calling.exe!main() Line 28
       [External Code]
       [Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]

    Double-clicking on each of those lines in the Call Stack window essentially takes me to the line it said it would (e.g. double-clicking Calling.exe!CallC() Line 8  takes me to Line 8 of the code). I’m confused, however, on why those lines were chosen. Line 8 is the opening brace for function CallC(), Line 16 is the closing brace for function CallB(), and Line 21 is the call to CallC() in function CallA(). To me, I don’t see any similarity or pattern between those lines, so I’m curious as to why Call Stack would take me those certain parts of the code.

  • raj

    hi there,
    thank you for your tutorials. while i was learning this debugging chapter i followed your instructions but the thing is when i follow your instructions exactly i am not able to understand this topic(may be because i am usng the latest ver of codeblocks 16.01 ) and the explanation u have given is mainly for VS. can u please also add the explanation to CB also along with some images.

  • sdmv

    I have a doubt
    When i set "run to cursor" to the beginning of the x variable assignment instead of the first cout statement the watch shows the value of x as -858993460.
    Why does this happen?

    • Alex

      858993460 is 0xCCCCCCCC in hex. When you run a program in debug mode, C++ initializes stack memory to this value. Since your variable is declared on the stack (we’ll explain what this means in the future), it gets the value 0xCCCCCCCC by default. In release mode, this doesn’t happen.

  • Paul

    Hey Alex, I want to say thank you for the phenomenally excellent tutorial on how to learn C++, I’ve tried multiple other tutorials for various different languages, including C, Python, C#, BASIC, Java and probably others I’ve forgotten, and none of them have been as easy to follow as this.

    I’m a fast learner, I pride myself on that, and I can learn from reading, hands on practice, and being shown how to do something, but no other learning resource for programming has helped me grasp the concepts as well as yours has.

    I was considering giving up trying to learn programming at all until I came across this website, and being explained concepts thoroughly before being asked to use them has boosted my confidence so much, and I’ve learned more in the last 4 days than I have in the last year since starting to learn programming.

    I have been able to implement an if else function in a practice calculator designed to catch a user trying to divide by zero, and I have been toying with trying to catch an exception with a user entering the wrong option when choosing the operand, I have implemented it, but it doesn’t catch the error until after trying to perform the calculation instead of when the user enters the option for the desired operand, and it doesn’t ask the user to try again, it’s included below in the else if statement.

    The divide by zero if else statement isn’t perfect, but it does return an error message to the user, and returns -1 when the error is caught, my attempt is below if anyone is interested.

    I’m sure many smarter people than me will point out how to improve this, and honestly I welcome it, but for something that I’ve done by myself, I’m very proud of it and the rest of the code for the calculator, before reading your tutorials doing that trying to implement that simple bit of code would have frustrated me and left me wanting to quit, so the fact I can even do something this simple after less than a week of learning with your tutorial is a source of pride for me.

    In fact I just realised that I can improve the above code by using || instead of using multiple && for the else if statement.

    I’m even more proud of myself for that.

    my very best regards, Paul

    • Alex

      I’m glad you’re finding the tutorials helpful.

      One quick note:

      evaluates as:

      Which isn’t what you want. You probably meant:

      For readers who don’t know what operator || and && are, we cover them in chapter 3. 🙂

      • Paul

        Yeah, you’re right, I’ll note that for future use, but that else if statement was something I sort of figured out myself and edited it in just before I hit post.

        I already had some prior knowledge of || and && from other programming tutorials before I posted that, but as you can see, I’m still not quite there yet, so thanks for pointing that out, it might also help others who’re reading these lessons, and help them to avoid a similar, albeit minor, mistake.

        In any case though, I am thoroughly loving this series, I will admit that I was starting to struggle with the stuff in chapter 4, so I decided to return back to chapter 1 and go over it again and reinforce the concepts covered until I get back to where I was.

        I really need to learn to slow down instead of going ahead when something clicks.

        I was just wondering though, wouldn’t you be able to remove some of the redundancy from that else if statement by typing

        instead of typing "operand !=" multiple times?

        I have a feeling that it would have a very different meaning to the compiler than what your version does, but I wanted to be sure from someone more knowledgeable than me. 😀

        Thanks for the reply! 🙂

        • Alex

          evaluates as:

          which evaluates to:

          Probably not what you had in mind.

  • Kiran C K

    Hey Alex,
    This is my second round of going through this entire tutorial. I am trying to grasp what I have missed / forget / to become more convenient with the language. I find debuggers to be very useful with procedural programming. But in OOPS, it seems to be not of much use. Can you comment on this? I am asking this question way ahead of OOPS lesson because debuggers are not discussed after this lesson.

    • Alex

      I’m curious as to why you think debuggers are less useful in OOP. I find them to be just as useful (maybe more so in some cases, since it’s not always obvious what function is being called when you have virtual functions).

      • Kiran C K

        I am adding one of the example programs that you have added in one of the future lessons.

        When I used the C++11 debugger using codeblocks, all that the debugger points to is main and when I click on ‘Step into’ it points to the child class and that is it. I had just 2 debugging steps I had for the entire program. But in procedural programming, it points to each instruction

        • Alex

          I think you may be doing something incorrectly. When I debug this program and press step-into (f11) in Visual Studio 2015, it stops at the following lines:
          * { (in main)
          * Derived cDerived
          * Base &rBase = cDerived
          * std::cout << "rBase is a " << rBase.GetName() << std::endl; * Derived::GetName() * The template for operator<< (at this point, I step out) * The template for operator<< (at this point, I step out) * return 0; * } (main)

  • Strong

    hi alex,

    how can i watch my 2d array in gdb terminal ?
    i can watch my 1d array with  : display *arr@5 . but IDK HOW to set the column and row to display in 2d array

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter