Search

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?


D.2.1 -- Fundamental variable definition, initialization, and assignment
Index
3.10 -- Finding issues before they become problems

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

  • Maura

    Please better explain on Question #3 why the answer for the call stack is
    d
    b
    a
    main

    and not instead
    d
    c
    b
    a
    main

    • 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:
      d
      b
      a
      main

      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:

    readNumber():

    main():

    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]