DOUG LLOYD: So if you're anything like me, when you write code
it's not always going to be perfect.
There's usually going to be something wrong with it.
And that is known as writing bugs.
And part of being a computer programmer is
learning how to debug, or remove the bugs, from programs.
And there are a lot of different techniques and strategies
that one might use to do this.
And what I want to do in this video is show you
three of the tools that are baked into CS50 IDE
that you can use to help with your debugging,
or help trying to figure out what's going on in your system.
And these three tools, which I'm going to just display the names of here,
are known as debug50, eprintf, and help50.
We're actually going to cover those in reverse order.
So we're going to start with help50.
So I have a couple of files pre-configured in my IDE.
I'm going to navigate into my help50 directory.
And just clear the terminal window here.
And what help50 basically does, it is designed
to be sort of a virtual teaching fellow of sorts.
It basically is trying to give you clues and hints about what might be going on
in your program or when you're trying to work with your program
and something goes wrong without just giving you the answer outright.
So it's trying to nudge you along in the right direction in the hopes
that it's an issue that, with a little bit of encountering and having
the computers sort of give you a little bit of back and forth,
it's an issue that you'll learn to be able to not recreate in the future.
So I have a couple of example programs here.
All of them are written in C. And let's just try and compile the first one.
So let's try and make example one.
Error.
So this is where help50 is going to come in handy.
Generally it's going to be used when you're working.
It's not so much a bug in your program that is
during runtime, a runtime error.
This is going to be a logical bug, or some kind
of bug that prevents your program from being compiled
is going to be the most common use case of help50.
So here I'm getting told I'm implicitly declaring library function
printf with blah, blah, blah.
There's a whole lot of text there.
Now, what help50 tries to do is it looks at that error message for you.
And if there are multiple ones it will look
at the first error message for you.
And it will try and translate that kind of arcane language
into something a little more, hopefully, intuitive to use.
And the way we use help50 is pretty straightforward.
We first type help50, and then we do exactly the command we tried to do.
So in this case it's help50, make example1.
Let's see if maybe help50 can give me a little more information about what
I might be doing wrong in my program.
So I run it again.
Now, I'm getting this sort of hint from the virtual TF,
which is written here in yellow.
"Did you forget to #include stdio.h in which printf
is declared atop your file?"
Well, let's take a look.
So in example 1.c, it looks like I did kind of forget to do that.
So if I just go ahead and add that, and I save,
and I try and make example one again maybe.
Hey, it compiled.
It worked just fine.
So I can now run the example1 program, hello world.
Now, of course, I have a logical bug here where I didn't put a backslash n.
So it kind of ran into a new line like that.
But that's OK.
That's something I can go ahead and fix pretty easily.
So let's try and compile example two.
And we'll go through this again where we won't look at the source code
beforehand.
We'll just try and compile it, thinking we're pretty close,
and see what happens.
So we'll try and make example2.
Oh.
Seven errors generated.
That's not good.
But, again, help50 can help us here.
And what it's going to do in this case is
it's going to look at the very first one and give us a hint for that one.
Now, oftentimes when you get a lot of errors from compiling
it's not necessarily that I've done seven things wrong.
In fact, if you look at the program you'll
see that it's not that many lines of code when we do.
But really it's just one error that sort of cascades and creates
another one because it doesn't understand what's happening before.
And if you can fix that one error at the beginning,
it might resolve one or more, or all, of the remaining errors.
So I'll clear my terminal window.
And we'll try this again.
But we'll preface this by saying help50 first.
So help50 make example2.
Let's see.
Use of undeclared identifier string.
Did you mean standard in?
Well, I'm assuming probably not.
Let's take a look at my code.
No.
I meant to use string there on line five.
So by undeclared identifier, Clang means you've used a name string
on line five which hasn't been defined.
Did you forget to #include cs50.h in which string is defined atop your file?
Well, here, again, I did.
I did forget to include cs50.h this time.
So it gave me another clue here.
But I had seven errors.
So hopefully this resolves most of them.
Lets clear this and see if it does.
We'll try and make example2 again.
And it did.
So even though it said I had seven errors, I really didn't.
I just had the one.
And because that one kind of threw everything else off,
it just kind of cascaded down and really messed us up.
All right.
Let's take a look at example three.
We'll try and make example three.
Seven errors again.
Ugh, man.
Let's see what I got here.
Looks like I have a for loop that's going from 1 to 10.
And it's supposed to print out a new integer on each line.
That looks OK to me, at least at first glance.
I don't really know what the issue could be here.
But help50 might be able to help us out again.
So we'll try one more time help50 make example3.
And, again, you'll see that help50 is commonly
going to be used most of the time-- although it's not all it can do.
And we'll take a look at a couple of examples of that in a second.
You're going to use help50 most of the time when there are compile time
errors that prevent your program from being compiled
and have to be resolved first.
So we'll try and help50 this one.
Looks like it says on line five it looks like you're
trying to declare a variable that's already been declared elsewhere.
I don't see that.
But then it tells me a little bit more.
If you meant to create a for loop be sure that each part is separated
with a semicolon rather than a comma.
So here I've got commas, and I'm supposed to have semicolons.
So it's, again, little things like this where it's little syntax things where
if you were able to get in touch with somebody
you could just kind of look at your code really quickly and be like,
oh, well, you really just need to put in a semicolon here instead of a comma.
That's the kind of thing where it stinks to get stuck in a jam where you're just
waiting for somebody to give you that sort of shining moment right
where suddenly the error is revealed.
You can use help50 to try and help you along and accelerate this
so that you don't get stuck waiting, and you can get a little resolution
for your errors a little more quickly.
Of course, we'll just confirm with trying to make it again.
And it compiled no problem.
I could run this program.
And it will print out the numbers 1 through 10, each on separate lines.
We can't see them all here because my terminal window is not big enough
to hold them, but they're all there.
All right.
I got one more example here.
And then I'll show you two examples of using help50 not in the make context
necessarily, or in the Clang context.
So let's try and make example4.
I have one error.
"Expression result unused, n times 5."
Not really sure what that means.
So let's just quickly pop open example4 here at the top.
Looks like what I want to do is have this print out 50.
So I set n as equal to 10.
I multiply n by 5 to get 50.
And I want to print out 50.
So I wonder what the issue could be.
So let's help50 make example4.
On line six of example 4.c you are performing an operation,
but not saving the result. Did you mean to print or store
the result in a variable?
So remember, when we are doing mathematical manipulations
to variables, we always have to assign the result to something.
And here what I probably meant to say is either n equals n times 5,
to change n from 10 into 50, or the more shorthand version,
n times equals 5, which would also work just fine.
So I can save this.
Hopefully this fixes it.
I'll try and recompile it.
And I'll try and run it to see if I get 50 printed out.
So that's a couple of uses of, in particular
this is help50 helping with Clang.
Although every time we were doing this we were typing make.
Remember that make is actually just a wrapper
for Clang, which is the name of the actual compiler
that we're using in CS50 IDE.
What happens though if I try and do this?
There's no file called example5.
So make example5.
Unlike the previous four, this is actually
going to be a help50 that helps with a message
from make as opposed to a message from Clang.
Now, obviously it's not there.
So you can probably figure out what it means.
But in case you didn't, I could preface it with help50.
"Do you actually have a file called example5.c in the current directory?"
Well, I don't.
So I'm trying to compile a program that doesn't exist.
So this is just help50, again, giving me a clue,
like, well, maybe you're making a little bit of a mistake here.
And it's true.
I am making a bit of a mistake.
One more example here.
Let's say that I want to change directories into another directory.
So I want to ls example6.
There is, again, no example6 here.
"ls cannot access example6, no such file or directory."
Again, help50 might be able to help with this.
So I'll preface it one more time.
Are you sure example6 exists?
Did you misspell example6?
It doesn't exist.
Maybe I had typed it wrong and I thought it was working.
So it's just a reminder.
Did you check that?
Oh, maybe I had misspelled it.
Maybe I meant to do something else, and then I can take a look.
Now, help50 is a tool that is still in development.
We actually have an open source GitHub repository.
So as you go through the class and you become more comfortable, particularly
as you start to learn Python, which is the tool that help50 is written in,
you can actually head to CS50's public GitHub repositories and take a look
and see what types of error messages that
are a little more arcane that we're trying to catch and have help50
explain in more human understandable terms
so that if you want to contribute to that you actually can.
And if you encounter an error that you're not
getting, that help50 doesn't understand, and you want to report that error
and hope that somebody else maybe can help match it,
you can do that through that platform as well.
So this is definitely a collaborative tool.
And we welcome you to continue to contribute either solutions as you
become more comfortable, or issues that we can try and resolve
to make it a more robust tool.
All right.
So another tool that we have is one called eprintf.
Now, it's really common when you are starting to debug your programs to kind
of pepper them with printf statements.
It's sort of like a sanity check where you're checking,
OK, well, this line printed.
And then I have some lines of code that run.
And then this line printed.
Like you're trying to figure out where things are going wrong.
The trouble with printf is it doesn't necessarily tell you
where the program is going wrong.
You have to kind of go back and scroll through your source code
to figure out which error message corresponds to that.
That's not always that helpful.
It's not a huge deal.
But we have this tool that makes it a little bit easier.
So it's called eprintf, which stands for error printf.
And I'm just going to navigate into my eprintf directory
where I have just one example file.
I'm going to open that up here and show you what it does.
So not much to this.
I'm going to scroll up here.
Basically what I'm doing is I'm asking the user to give me an integer.
And then I actually get that integer from them.
And then I have eprintf, integer obtained.
Now, this means nothing to the user.
It's an error message to make sure for me,
as the person who's testing this program, that I got to this point
in the program.
And we'll see exactly what eprintf does that gives it
a little bit of a leg up over printf, which is just
going to display to the terminal.
Then I'm doing a couple of different things.
If x is less than 0, I'm going to print x is negative.
If it's greater than zero, I print x is positive.
Otherwise I print x is 0.
And then I have one more eprintf call at the bottom here
which is got through the program.
So if I see that eprintf, that means that I've succeeded
and I've gotten through every single line of the program without crashing.
So let's just quickly compile this with make eprintf.
And we'll try and run ./eprintf.
Please give me an integer.
Let's give it 50.
And look at the little difference here.
So instead of just printing out what I said, it tells me where it came from.
So it tells me what line it came from and what file it came from.
As we write more and more complex programs later in the course,
we might write programs that span multiple .c files.
We might have eprintfs throughout them.
So it's just a useful way to figure out exactly from where in your program,
or as things are going through, where in your program
the error message that you're seeing, or sort of the printf
prompt that you're seeing comes from.
So it's definitely a good tool to familiarize yourself with,
particularly earlier on where you might not
need the more complex tools of a debugger, which
we're going to talk about in a second.
But you just want to get sort of a sanity check
to make sure that things are working the way you expect them to.
OK.
And the third and final tool that we're going to cover in this video
is debug50.
Now, debug50 is a GUI or Graphical User Interface
wrapper for a tool known as GDB, which is a very richly developed debugging
platform.
And it will really help you take a look underneath the hood,
inspect what is going on in your program,
and try and figure out where things might be going wrong.
In this example we're going to cover three different buggy videos.
And I'm going to show you how to use debug50
to sort of give you some clues as to what you might need to do.
So the first thing I'm going to do here is navigate into my debug50 directory
where I have three source files and three programs that are previously
compiled.
So these have compiled.
I don't need help50 to tell me what's going on here
because I've already got the compiled binaries here.
But there's something going wrong in these programs that
is not what I expect.
So the first thing I want to do is run debug1's program,
and then we'll take a look at debug1's source code.
And then we'll take a look at how debug50
can give us a little bit more information about what
might be going wrong here.
So here's what we're going to do.
We're going to go, and I'm going to clear my terminal really quick,
and we're going to run debug1's binary.
Provide a number.
OK.
I'll provide one.
You gave a one.
Seems pretty good.
Let's try this again.
Provide a number.
I'll give it two.
You gave a one.
That's not right.
Zero?
You gave a one.
So it's always saying, I gave a one.
I did.
I gave a one the first time.
So let's maybe take a look at what's going on here.
So I have my program.
I'm providing a number.
OK.
That works.
If x is one, say you gave a one.
Otherwise, apparently I'm not doing anything.
It's not supposed to print anything if I didn't give it a one.
So that's weird.
So at this point if you're familiar with the code
you might see where the issue is here.
But let's pretend that we don't.
Or maybe you don't.
And that's totally OK as well.
This debug50 tool can hopefully give a little bit more information
and we can see what's happening.
So what I want to do is the first thing you
need to do when you're working with a debugger
like GDB is to provide a breakpoint.
What a breakpoint is is basically your program
will execute until it hits that line of code.
And then it will stop, or break, and wait for something to happen.
If you don't know where to break in your code,
because you don't even know where the issue might be happening,
it's totally reasonable to break at main.
The way that you set a breakpoint is right here to the left of the line
numbers you'll notice that my cursor turned into a little like pointer
finger there.
If you click once, you get this sort of red light, or a stop light.
That's basically your indicator that you have set a breakpoint.
So my program will compile, and it will run until it gets to line six.
At which point it's going to kind of freeze.
And from there I can make very slow steps through my program.
Usually when we're running our program it's like you compile it,
and it's done.
Here we can really force it to slow down, and look
what it's doing line, by line, by line, and see if we
can see where the issue might lie.
So I've set a breakpoint.
Now I need to run debug50.
debug50 ./debug1.
Cause that's the name of the program that I wanted to test.
Hit Enter.
And if you've watched our CS50 IDE tutorial introduction video
you noticed I talked about the debugger tab.
You'll notice the debugger tab on the right has popped open.
And I'm giving a little bit of information here.
I have information about the call stacks.
So if I had multiple functions being called
it would tell me which function I'm in at the time,
and which functions are waiting for stuff to happen.
Local variables in my program.
There are values.
What type they are, and so on.
Really useful stuff.
And my program has frozen, right.
It has not printed out "please provide a number."
It's just waiting for me to do something.
And the way I can control what my program does is up here at the top.
I have resume, which is basically just going to speed through my program
again, ignoring any more breakpoints.
I have step over, which is going to move one line ahead.
And generally you're going to want to step over any functions
that you did not write, because if you step into them, which
is the next example, it's actually going to go and look at printf's code,
and start executing printf's code one line at a time.
And we can probably assume that printf is OK.
And we can probably assume that getint, for example, is OK.
So we don't need to step into those.
We can step over them.
If you're going into a block, for example, like an if, or a function
that you wrote, you might want to step into it,
unless you happen to know for sure that it's not an issue in that function.
So you can start to proceed through those a line at a time.
And then, lastly, there's step out.
We're not in anything right now.
So we can't step out.
But if you step into a function and you realize,
oh, I really shouldn't have done this, you can step out,
which will just proceed through the rest of the function,
and then pick up again at the next logical spot.
So what I want to do here is start to proceed one line at a time.
So I want this to print out "provide a number."
So I'm going to step over this line, which is going to execute it.
You can see it at the terminal there at the bottom.
Then it's prompting me to provide a number.
So I'll give it a three.
One seems to work.
So I'm going to give it a three.
And I'll hit Enter.
And then I will again step over.
If x equals one printf.
You gave a one.
So I kind of want to step into this.
And in particular, notice what's going to happen here.
Notice that right now it says my variable x
has a value of three, which is what I expect.
But as I step into this, the value of x has changed to one.
It's no longer three.
So this statement is now true.
It says, well, x is one.
So you gave a one.
And if I step over, that is what it will do.
You gave a one.
And if I stop one more time, the program finishes executing.
Did you happen to see what the error there was?
It's a silly little syntax thing.
But I used a single equal sign instead of a double equal sign.
So what I really did here is I assigned x to be one.
Regardless of what x was at this point, I said x is equal to one.
I assigned x to one, when I really meant to do this.
If x equals equals one.
And now let's just save this program really quickly.
And we'll recompile it, because we have to recompile
a program if we want to rerun it.
Use equals to turn this comparison into an equality assignment.
Now, the reason that this works is because I had put
this extra set of parentheses in here.
Generally if you tried to do this it wouldn't work.
But I had to force it for purposes of this example.
So I had to get rid of those parentheses as well.
We'll try one more time to compile this program.
Now it compiled successfully.
We'll clear our terminal window.
And let's try and debug50 one more time, just
to make sure that everything is working the way we expect.
We still have our breakpoint set at line six.
So it's still going to freeze at the first possible opportunity after that.
I want to step over this to provide a number.
I'll give it three again.
Step over.
x is now equal to three.
You can see here on the right.
Now, let's step into this.
Can't step into it.
Why?
Because x is not one anymore.
So that next line of code on line 13 there
is not going to execute because the condition is no longer true.
So before I was assigning x to be one.
And that's why it would go in.
And thanks to debug50 I was able to see, oh, wait, this three
is unexpectedly changing into a one.
Maybe there's something going on wrong in that area.
So that's one way that debug50 was able to help isolate where in the program
things were going awry.
All right.
So I'm going to hit Resume here just to end the program,
have it finish doing its thing.
Didn't print anything because we didn't have a one.
And now let's take a look at program number two.
So I'll clear my terminal.
And let's try and execute the debug2 program.
"What percentage grade did you get as a number?"
Well, let's say maybe I wasn't doing so great in CS50 and I got a 50%.
My grade is an E.
OK.
But let's say maybe I'm doing a little bit better and I got a 75.
So that should hopefully be like a C. Eh, I got an E.
Wait a minute.
What if I got like an A, I got everything?
E.
Well, again, this isn't doing exactly what I expected it to do.
So let's take a look at the source code.
And then let's take a look at debug50 and see if maybe it
can give us some clues here.
So I'll open up the source code for debug2.
And I'll just close this one here.
And I'll also just clear the terminal screen one more time.
All right.
So what percentage of the grade did you get as a number?
Get an integer.
What's happening here on line eight is I'm just
transforming whatever the user gave me into a multiple of 10,
so that divided by 10 times 10, that's a trick that
works because of integer division.
But say the user gives me 93.
93 divided by 10 is nine, not 9.3.
Remember, its integer division.
And then 9 times 10 is 90.
So I'm just basically dropping off the ones place of every number
here and just transforming it into a multiple of 10.
And then I have a letter character for a grade.
It will get stored there.
And then I'm using a switch statement, which
is one form of conditional statement, to look over the different possibilities.
So if I have a 90 or a 100 after executing lines seven, eight,
grade should be an A. If I have an 80, it should be a B, a C, a D, and an E,
depending on what my scores are.
But it seems like every time I'm doing this I'm getting an E.
And, again, if you're familiar with switch statements,
you might see what the issue is here.
And if you're not familiar with switch statements, that's OK.
Because switch statements are a little bit strange the first time
you use them.
But debug50 can help us figure out what is happening here.
So first thing we got to do, of course, is we got to set that breakpoint.
So I got to figure out where I want to set it.
Well, it looks like I might have already set it here at line 11.
And that seems like a fair enough place to do it.
So let's set our breakpoint there.
So our program will not freeze and pop open for us
until we get to that point in the code.
So we'll use debug50 on the debug program number two.
"What percentage of the grade did you get as a number?"
So let's say I got 100.
And now we're frozen.
And notice over here, grade has been set to negative one.
There's no value there.
But that makes sense, cause we haven't assigned grade equals something yet.
Percent is 100 and 10th is 100.
So we have the value we're expecting.
10th is 100, which means when we get to line 13, grade A should get triggered.
So let's step in one line at a time.
All right.
So notice that my grade is A. And then it's B.
And then it's C. And then it's D. And then it's E. And then if I step over,
that's what now gets printed.
And that's not what I expect.
So it seems like by using debug50 to step slowly
through my program, what was happening is
I wasn't just triggering the one case that I wanted to hit.
I seemed to be hitting all of the different cases.
And the grade kept changing.
It started out at the right thing.
It started out as A. And then it became B, and a C, and a D, and an E.
And the reason for that, and again, we'll cover this on our video
on conditionals if you haven't seen it already,
is that at the end of every case option for a switch I needed to have a break.
I only ever want one of these things to be true.
Now, it's true that you might end up in a situation
where you actually want the behavior of falling through the cases,
as it's known.
But that's not what I want here.
I want explicitly to be assigned one value.
And then I don't want to look at the rest of the options.
So what happened here is I just fell through.
I kept executing every line of code from case 100 down.
If I had started out at 80, it would have given me a B, and then
a C, and then a D, and then an E. And if I started out at like a 60,
it would have given me a D and then an E.
So I don't want that.
So I have to include break statements at the end of all of my different options
within the switch.
And if I save this and I recompile it, and I clear my terminal
and run it one more time, if I get 100, now I have an A. All right.
That's good.
If I get an 80, I have a B, and so on.
And so, again, by using the tools this time
of seeing that I was hitting all of these different lines of code,
not necessarily that variables were changing--
although it was useful to see that A was turning into B
and turning into C. What was more useful for me there anyway was seeing
that I was hitting all of these lines of code
that I shouldn't have been hitting.
I should have only been hitting the very one, which
was case 90, colon, case 100 colon.
Because that was what I had typed in, a 90 or a 100.
So it was strange that I ended up falling through.
And being able to see it go line by line,
as opposed to just the program running so quickly because it's so short,
that was a good clue for me.
We have one more buggy program.
And let's take a look at that one and see if debug50 can
help us figure that one out as well.
So I'll close this code window here.
And let's run debug3.
How many stars?
Five.
Give me six.
How many stars?
Zero.
it gives me one.
How many stars?
40.
Well, I'm not going to count that, but it's 41 is what it is.
So I'm getting a few too many stars.
But if I look at my debug3 source code, I'm going from zero to x,
and I'm printing out a star for every time.
So it seems like that should be working just fine, but it's not.
So maybe the debugger can help us figure this out a little bit more cleanly.
So let's pop it open.
Let's first set a breakpoint.
It seems like the integer part is maybe not working.
So instead of setting it to breakpoint after that,
maybe it somehow is turning five into six?
I don't know.
Let's set our breakpoint before that.
Let's just set our breakpoint right at main.
And there was a breakpoint here.
We'll just get rid of it.
You can double click on a breakpoint to make it go away if you
don't want to use that one anymore.
And you can also set multiple breakpoints.
We're not doing it in these examples.
But I could set a breakpoint at first spot,
and then maybe another one a little bit later on.
It would stop at that point as well.
All right.
So let's try and compile this.
So really quickly recompile.
And then we'll run debug50 to take a look
at what's happening in this program.
All right.
How many stars?
So, again, we broke at main.
So it's going to freeze at line six and wait.
If I step over this line, it will print out how many stars.
Let's say that I want five.
Then we'll step over this.
Because we don't need to step in to get in presumably.
And when we get through, I's value is 32,677, which is actually OK.
It hasn't been set yet, because line nine has not executed.
But x is five.
It didn't somehow transform into six.
So what I now know at least is that my error somewhere
happens from line nine down.
It's not line six.
It's not line seven.
It's got to be after that, because x has the correct value.
It has five.
It didn't somehow get transformed into six.
But I's value is 32,767.
This is a red herring.
This is not a bug.
Like I said, line nine has not executed yet.
Once line nine executes then I will be set at least to zero,
as we'll see right now.
So we'll step into this loop.
Notice now I is zero, which is what we expect.
Then it will print a star.
I'm going to step over that, because I don't want to step into printf.
So we'll step over.
Notice that it printed one star to the terminal.
Step again.
I is now one.
That's what we expect.
We went through one iteration of the loop.
I incremented by one.
I'm going to step over.
Print.
OK.
Two.
Three.
Four.
Now, at this point I should be breaking, right.
I'm going from I is equal to zero to I is less than or equal to x.
Uh-oh.
I see my bug now already, right.
I'm counting I is equal to zero to I is less than or equal to x.
So I saw it even before debug50 saw it for me.
But it's true if I step into this loop, now I's value is five.
So it should have stopped if I did what I intended, which is I is less than x.
But it actually went into the loop, which
means it's going to execute this line of code again.
And now it's true that if I step into this, I goes away, right.
Because if I became six, this loop would no longer run.
So it goes away.
And I break out of the loop.
And I jump down to line 12.
But I've printed out six stars instead of five.
Now, again, these examples are a little bit contrived
for the purposes of showing you how to use the debugger.
It's not supposed to necessarily find the bug for you.
But it's supposed to slow the computer down enough that you
can see the steps that it's doing.
So the values on the right, being able to track what values variables
have is useful.
Also I didn't show this, but you can actually change the value of variables
if you want.
I could say x is equal to 23.
I could do this in the middle of my program running,
between doing different lines to change things,
to see if the behavior is affected in any way.
It wouldn't have been that useful here because I've already
broken out of the loop.
But if I wanted to somehow make it artificially print more and more
because I haven't figured it out yet, I can do that.
You can do that with any local variable there as well.
You can use this to inspect strings and arrays as well,
which we're not going to get into here, because this is just
supposed to be a general tutorial.
But, again, the goal is not so much to be, here's the bug.
It's to slow things down enough that you can see exactly what the computer is
doing, and see if at any point it deviates
from what you expect it to be doing.
And that's what all these debugging tools are used for,
particularly this GDB based one called debug50.
But eprintf.
Make sure that your program is printing out
sort of sanity check messages in the right spot.
help50 is supposed to give you some clues about where
you might have compile time errors.
And debug50 is supposed to help you figure out
where your runtime errors are.
So use all these tools in conjunction, and you'll
be well on your way to debugging code like an expert in no time.
I'm Doug Lloyd.
This is CS50.