3.x — Chapter 3 summary and quiz

Quick Summary

A syntax error is an error that occurs when you write a statement that is not valid according to the grammar of the C++ language. The compiler will catch these.

A semantic error occurs when a statement is syntactically valid, but does not do what the programmer intended.

The process of finding and removing errors from a program is called debugging.

We can use a five step process to approach debugging:

  1. Find the root cause
  2. Understand the problem
  3. Determine a fix
  4. Repair the issue
  5. Retest

Finding an error is usually the hardest part of debugging.

Static analysis tools are tools that analyze your code and look for semantic issues that may indicate problems with your code.

Being able to reliably reproduce an issue is the first and most important step in debugging.

There are a number of tactics we can use to help find issues:

  • Commenting out code
  • Using output statements to validate your code flow
  • Printing values

When using print statements, use std::cerr instead of std::cout. But even better, avoid debugging via print statements.

A log file is a file that records events that occur in a program. The process of writing information to a log file is called logging.

The process of restructuring your code without changing what it actually does is called refactoring.

unit testing is a software testing method by which small units of source code are tested to determine whether they are correct.

Defensive programming is a technique whereby the programmer tries to anticipate all of the ways the software could be misused. These misuses can often be detected and mitigated.

All of the information tracked in a program (variable values, which functions have been called, the current point of execution) is part of the program state.

A debugger is a tool that allows the programmer to control how a program executes and examine the program state while the program is running. An integrated debugger is a debugger that integrates into the code editor.

Stepping is the name for a set of related debugging features that allow you to step through our code statement by statement.

Step into executes the next statement in the normal execution path of the program, and then pauses execution. If the statement contains a function call, step into causes the program to jump to the top of the function being called.

Step over executes the next statement in the normal execution path of the program, and then pauses execution. If the statement contains a function call, step over executes the function and returns control to you after the function has been executed.

Step out executes all remaining code in the function currently being executed and then returns control to you when the function has returned.

Run to cursor executes the program until execution reaches the statement selected by your mouse cursor.

Continue runs the program, until the program terminates or a breakpoint is hit.
Start is the same as continue, just from the beginning of the program.

A breakpoint is a special marker that tells the debugger to stop execution of the program when the breakpoint is reached.

Watching a variable allows you to inspect the value of a variable while the program is executing in debug mode. The watch window allows you to examine the value of variables or expressions.

The call stack is a list of all the active functions that have been executed to get to the current point of execution. The call stack window is a debugger window that shows the call stack.

Quiz time

Question #1

Use the integrated debugger to step through this program and watch the value of x. Based on the information you learn, fix the following program:

Show Solution

Question #2

Use the integrated debugger to step through this program. For inputs, enter 8 and 4. Based on the information you learn, fix the following program:

Show Solution

Question #3

What does the call stack look like in the following program when the point of execution is on line 4? Only the function names are needed for this exercise, not the line numbers indicating the point of return.

Show Solution

Author's note

It’s hard to find good examples of simple programs that have non-obvious issues to debug, given the limited material covered so far. Any readers have any suggestions?

4.1 -- Introduction to fundamental data types
3.10 -- Finding issues before they become problems

28 comments to 3.x — Chapter 3 summary and quiz

  • Mike

    For Quiz #2, I copied and pasted your sample code twice now, and it compiles and executes, but as soon as I press enter after entering the second number, it crashes every time with a Windows error that my test.exe has stopped working. One of my options is "Debug the Program" which I thought was fitting considering this chapter. I tried it, but it seems way to advanced for me.

    Any suggestions as to why this is happening? BTW: I'm using Visual Studio 2019.

    The Exception code is c0000094, if that helps. I just googled it. Appears it may be related to dividing by zero. But why, I entered 8 and 4 as per your instructions?

    • It's supposed to crash. The purpose of the quiz is that you figure out why. You can solve it by reading the code too, but you won't learn how to use the debugger that way.

      • Mike

        Ha! too funny! I guess I just wasn't expecting a full blown crash of the program at this point, though it makes perfect sense. Can't wait to try to debug it now!

        Sorry for wasting your time on this one.

  • Jose

    Hi, question #3 shows the functions sorted this way:

    but if I had to write that code I would have sorted them this way:

    Is there any rule/best practice about sorting the functions called from main()?

  • Joe Das

    Outstanding Tutorial. You are really helping me get my old coding chops back so quickly, and your discussion points about good working practices are invaluable.

    You were asking about nasty problems in debugging: An example which will quickly aggravate coders but which does happen is when a variable is misspelled because it is declared twice by similar names and the wrong variable is used in a function. This would tie back into your recommendations about variable naming. This can be made even nastier with confusing pre-processor statements >:D.

    • Alex

      > An example which will quickly aggravate coders but which does happen is when a variable is misspelled because it is declared twice by similar names and the wrong variable is used in a function

      Agreed -- that's pretty similar to quiz question #2, no?

  • Lawrence

    Why can't I add enter a value when I am stepping in during debugging?

  • NotJoeRogan

    Hello Alex or Nas,

    Let's say that I enter a breakpoint at line 7 of the program in the first question, and for the number I enter 4. Why is it that when I hover my cursor over all of the x variables throughout the entire program, they show a value of 4?


    • Alex

      When you hover over a variable, the debugger will show you the _current_ value for that variable, not the value the variable might have wherever you are hovering. This can be misleading the variable had a different value at the point you're hovering

      To do otherwise would require the debugger to remember what values every variable had at every point in the program, which would be significantly more complex, and potentially misleading in other ways (you might think you're seeing the current value when you aren't).

  • Maura

    Please better explain on Question #3 why the answer for the call stack is

    and not instead

    • Jason

      Because when the stack reaches function b, it begins it execution.

      First it reaches the call to function c.
      At this point the stack is c/b/a/main.
      However c does not make any calls and fully resolves itself.
      At which it returns to the next object in the stack b, and moves on to the call to function d.
      Thus the stack is d/b/a/main

    • Alex

      main calls a()
      a calls b()
      b calls c()
      c terminates
      b calls d()
      At this point we've hit our breakpoint.

      Working backwards, the functions still in memory are:

      c isn't in the list because it terminated and was removed from the call stack before d was called.

  • John Doe

    What about leveraging your example of function argument order of evaluation issues in chapter 2.3? It would be a weird scenario but would force the user to step through while debugging and see the flow issues in their stack. Testing in visual studio and gcc, this processed right to left, but clang did left to right.

    • Alex

      Good thought! However, the program would only manifest the problem on some machines and not others, making it a hard one to debug on machines that didn't exhibit the issue.

  • Louis Cloete

    Debugging exercise ideas: use "/n" for a newline somewhere instead of "\n" and watch the ensuing chaos when /n prints on the screen... ;-p

    Do something like this:

    [This next idea I borrow from my Delphi textbook. You will have to wait till after you've done loops, strings and arrays for this one.]

    The output line only executes once, because of missing braces around the intended loop body. The function prints only the last character of the string.

    • Hi!

      > Uninitialised variable causes undefined behaviour
      The value of @x is undefined, behavior is well defined.

      > next idea
      @s should be const and @i should be an @std::size_t (Or cast s.length()).
      This code wouldn't compile, because line 9 cannot see @c.
      I like this one. Even though compilers print a warning, it's a common mistake.

      • Louis Cloete

        About prtStrVertical():

        In Pascal, you must define all local variables for a function or procedure (Pascal's name for a group of statements that doesn't return a value) at the top of the function, so the scoping issue doesn't appear. To work around, either declare char c before the loop, or modify the function like this:

        The modification will cause a different, but related, bug.

    • Alex

      Thanks for the thoughts! The '/n' idea should be easy to diagnose by inspection. I'm trying to find things that are not quite as obvious to inspection, to validate the usefulness of having an integrated debugger.

      There are a ton of fun debugging problems once we do loops -- but alas, that chapter is a bit far off from this lesson. I didn't want to wait that long to introduce basic debugging topics.

  • Louis Cloete

    Question #1 solution:



    l. 18:

    Question #2:

    The problem could've been avoided if the program didn't declare and zero init variables, just to assign different values to them in the first place. A better solution would be to init x and y with the result of separate calls to readNumber(). I think the solution should reflect that. I.e. replace Lines 18 - 21 in the solution with:

  • Anthony

    For the note at the end, you could maybe add "debugging practice revisited" after some chapters since the basics have been covered. Would allow for some more intricate issues to solve and extra reinforcement for practicing good debugging habits.

  • Ethan Smith

    "The process of finding and removing errors from a programming is called debugging" i think you may have made a grammatical mistake there.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]