Lab 1: Debugging C with VS Code
In this lab, you’ll practice using VS Code’s C debugger.
The images in this lab are from Windows. The Mac and Linux versions of VS Code look similar to this, but not identical, so you should adapt accordingly.
What’s a debugger?
A debugger is a tool designed to help you debug your programs. Debuggers tend to have a lot of sophisticated features, but the core of what you need to know is this: a debugger allows you to run your program one line at a time, enabling you to examine your variables along the way. If you can watch your variables evolve one slow line of code at a time, you can usually track down your errors.
Part A: Setting breakpoints and inspecting variables
To get started, launch VS Code and connect to mantis. Go back and look at Lab 0 again if this process isn’t yet ingrained in your memory.
Now, let’s get started debugging:
-
Install the
C/C++ Extension Pack: Select theView->Extensionsmenu, search for theC/C++ Extension Packfrom Microsoft, and install it. -
Get a program to debug: Copy the
bitwise.csample to your working directory onmantis. You can do this usingFile->New Text Fileand then copy-pasting the contents. (Alternatively, you can use yourmantisterminal and a variant of thewgetcommand described in theStarting C assignmentto grabbitwise.c—it’s good to be comfortable using either approach.) -
Read the code: Take a look through
bitwise.cto see what it’s doing. How many numerical operations can you spot? -
Set a breakpoint: Once you have a copy of
bitwise.copen in VS Code, scroll to the functionexperiment1. At line 48, where it saysint b = a | bit;, hover your mouse to the left of the line number. You will see the ghost of a red dot. Click it to make that red dot solid.
![]()
When you run the program in debugging mode, the program will stop just before executing the line of code at your breakpoint.
- Start debugging: You can do this either from the
Runmenu or from the play-button-with-a-bug in the upper-right corner of VS Code.
![]()
Choose the first option:C/C++: gcc build and debug active file. After a moment to get things running, your program will stop when it first gets to your breakpoint.
- Stop and think: In the code, the line at your breakpoint is highlighted. This line has not yet executed.
Think for a moment before continuing: what value do you expect to be stored in the variablebafter line 48 executes?
- Look around for a minute: There is a terminal/console display at the bottom of the window, showing that the program has already produced some output, but has paused before finishing:
There’s also a debugging toolbar at the top with different debugging buttons, including a continue button to let your program continue from where it left off and a stop button for stopping the program. Hover over the buttons to see their names (and keyboard shortcuts).
Most important of all, in the upper-left corner of the VS Code window, there is the Variables panel, showing you the current values of the variablesaandbit, as well as the not-yet-computedb.
Finally, in the bottom left, there’s the Call Stack. What do you think this is?
-
Step through your code: When the program stopped at your breakpoint, you were in the middle of
experiment1()(how can you tell?). You can now step through your program one line at a time.-
Click the
Step Overbutton in the debugging toolbar. -
Look at the Variables panel. Did the variable values change the way you expected them?
-
Press the
Step Overbutton a couple more times until the next line to be executed (e.g., the one currently highlighted) is a call toprint_binary. Go slowly and pay attention to what changes after each click of theStep Overbutton. Now, instead of clickingStep Over, click theStep Intobutton. -
Look at the Call Stack panel. How did it change by moving into the
print_binaryfunction? How did the Variables panel change? -
Keep doing this as long as you want.
-
It is extremely valuable to be able to step through your code slowly to see whether it’s doing what you expect it to do. Get in the habit of doing this when you have a bug, but also even when you think your code is working. You can find a lot of subtle bugs this way.
- Done debugging: You can stop by clicking the
Stopbutton. You can get theFile Explorerpane back via theView->Explorermenu or clicking the appropriate button on the far left.
Part B: Debugging with multiple files and command-line arguments
You’ll now walk through debugging something more complicated, which happens to correspond to starting your next assignment.
Getting started
To start, let’s get the code. You can check out the assignment page or use the instructions I’ve copied here assuming you are continuing the lab and thus already connected to mantis.
-
In the VS Code terminal, make sure you’re in your
cs208directory (a.k.a. folder). If not, usecdto get to the right place, probably like this:cd ~/cs208 -
Use the
wgetcommand to download the starter code as a single.tarfile:wget https://cs.carleton.edu/faculty/tamert/courses/cs208-f24/resources/assignments/a3.tar -
Extract the
a3folder:tar xvf a3.tar -
Save any open files, as we’re about to change up your VS Code workspace.
-
Within VS Code, switch to that folder as your workspace directory by choosing
File->Open Folderand selectingcs208and thena3before clickingOK. You will probably have to re-enter your password. -
Re-open the VS Code Terminal (
Terminal->New Terminal). For me, this has my prompt ending in~/cs208/a3$. If yours is similar, you’re in the right folder. Let’s try compiling the starter code:
makeHere’s what my Terminal looks like when the compilation is successful:
tamert@mantis:~/cs208/a3$ make gcc -Wall -Werror -O0 -g -o bits bits.c main.c
-
Try running the code in the Terminal by typing
./bits to_lower abcDEF. This will use the provided code inmain.cto call theto_lowerfunction with inputabcDEF:tamert@mantis:~/cs208/a3$ ./bits to_lower abcDEF abcDEF
For now, all that
maindoes is print the result of callingto_loweron the provided input. We aren’t changing the string, so it prints the original string.
-
After class you should read the assignment directions carefully, and look through both
readme.txtandbits.h. For now, though, openbits.cand add a print statement to the beginning ofto_lower, printing outs:void to_lower(char *s) { printf("Input s: '%s'\n", s); // <-- new, not in starter code // TODO return; } -
Recompile and re-run the code. You should see your print statement reflected:
tamert@mantis:~/cs208/a3$ make gcc -Wall -Werror -O0 -g -o bits bits.c main.c tamert@mantis:~/cs208/a3$ ./bits to_lower abcDEF Input s: 'abcDEF' abcDEF
Debugging Assignment #3
Now that you are able to compile and run your code, let’s try debugging it.
-
Like before, start by setting a breakpoint, here on your
printfline into_lower. -
From the
Runmenu, selectAdd Configuration.
This will create a new.vscodefolder in youra3folder (look at the Explorer panel on the left), with alaunch.jsonfile inside of it.
- In the text editor panel, you should have
launch.jsonopen. It’s pretty empty now, but there is anAdd Configuration...button you can click on to fill it in.
Click that button and select{} C/C++: (gdb) Launch.
- There is now a bunch of lines after
"configurations": [. You need to change a few of the values:- Change the string after
"program":to be"${workspaceFolder}/bits". This specifies the program to run, just like when you run./bitsin the Terminal;${workspaceFolder}is the folder you have open in VS Code (which should be~/cs208/a3). - Change the array after
"args"to have the arguments you’d pass at the command line:["to_lower", "abcDEF"]. - Change the
"name"to something you like, such as"Debug bits.c". This is optional, but I like to recognize what I’m running.
- Change the string after
Here is a snippet of my file after these changes:
-
Switch to editing
bits.c. Make sure you still have your breakpoint into_lower. -
Start debugging. This time, select the debug configuration you just created (mine is called
Debug bits.c).
(No, I don’t know why it shows up on the list twice. I’m not sure what the difference is.)
- When the code runs and pauses at your breakpoint in
to_lower, take a look at the Variables panel. What does the stringslook like? It may help to expand the panel horizontally to see its full width.
A few more things to try
Here are a few more things to try out and ponder. It will be really helpful to you later to get comfortable using a debugger now, so I encourage you try them now, and revisit them if you’re having any issues later! You can also ask about these in office hours if there is anything I can help clear up.
-
What is the difference between the
Step OverandStep Intobuttons? Test this. Also, what happens if you try toStep Intoa C library function likeprintf? -
What if your program requires more command-line arguments? What syntax do you use in the
launch.json(config) file? -
Declare an array in
mainor some other function and break somewhere in that function. What does the array look like in the Variables panel? -
Download the sample
debug_this.cfrom the Samples page. This program has a bug. See if you can step through the program in the debugger (it’s just a single file, so you don’t need alaunch.jsonand can just pick the configC/C++: gcc build and debug active file), even if you find the bug from inspection alone. -
Also in
debug_this.c:-
Comment out everything in
mainexcept thereturnstatement. -
Add a call to
recursive_triangular_number(10)and aprintstatement to print out its result. -
Put a breakpoint somewhere in
recursive_triangular_number. -
Run the debugger.
-
When you hit the breakpoint, take a look at the Variables panel; is it showing what you expect? Also, look at the Call Stack panel; is it showing what you expect?
-
Click the
Continuebutton. You should land at your breakpoint again. How have the Variables and Call Stack panels changed? Repeat this a couple of times. -
Now, you should have quite a few function calls showing in the Call Stack. Click on each of them, and when you do, look at the Variables panel. What changes as you click on each function call? Explore, experiment, etc.
-
How would you explain the Call Stack to a CS 111 student?
-
-
Grab the sample
character_count.cand debug that; note that you’ll need to provide an input file, so this will require a new configuration in alaunch.jsonfile, with a filename as an argument in the"args"array. Put a breakpoint incharacter_counter.c’smainjust beforeget_character_countgets called. When your program hits that breakpoint, take a look at theinput_file_namevariable in the Variables panel. Make sure your Variables panel is wide enough that you can see both the numerical/address value ofinput_file_nameas well as the string that it points to.
That’s it!
There is a lot more to learn about using a debugger, but this should give you a good start. Keep practicing, and as always, ask questions you may have!











