Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
English
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (SoranĂ®)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Persian
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
DAVID J. All right.
This is CS50.
This is week one, because, of course, last week was week zero. And this is the
week where we'll actually start programming in a much more traditional
programming language we promised called C.
Of course, we started with this. And hopefully by now, with problem set one,
you've had a little bit of fun, even if you've played with it before. And the
goals of Scratch, beyond sort of making things feel very accessible and user
friendly, is really to elucidate some of the fundamental concepts that we'll see
again today.
And really, every week subsequently, like functions and conditionals and
and variables and so much more. And in fact, among the goals of Scratch is,
again, to kind of plant these visuals in your mind. So even as today onward
feels all the more like a fire hose, especially when it comes to really weird
cryptic textual syntax, the ideas are still going to be the same. So today,
program, Hello World, becomes this instead.
And in fact, just to color code things temporarily,
I dare say that what I've color coded here in orange, which looks probably, to
those of you who've never programmed, pretty cryptic, is the equivalent of the
when green flag clicked orange puzzle piece like this. What remains is just
line in purple with a bit of white, which is what ultimately is going to get
screen today to say hello world on the screen.
And of course, we had a name for something in purple.
In fact, if we rewind to week zero, this block in purple represented what type
of functionality?
A function itself, an action, a verb that gets the computer to do something.
what looked like this last week is about to look like this. Let's take away the
color coding and focus really on what we're going to now start calling source
code. So this is what programmers do.
in the real world. This is what software developers, software engineers do in
the real world. They write code that looks like this. And clearly, it's a
English -like, but it's not English in the way you would compose an essay or an
email. Clearly, there's some patterns and some special syntax to it that we'll
highlight ultimately today.
The problem is, though, that computers, of course, don't understand source code.
They only, per last week, understand zeros and ones. That is it, the so
binary system.
So somehow, we've got to get what already looks cryptic into something
looks at a glance even more cryptic than zeros and ones, the computers do
understand. And for today's purposes, just know that built into your Macs,
and phones, There is a built -in understanding of what these patterns
Maybe it means a number. Maybe it means a letter. But today, maybe it means an
instruction, like print something on the screen, or save something, or load
something. That is to say, computers use patterns of bits not only to represent
all the stuff we talked about last week, numbers, letters, colors, images,
sounds, and all of that. They also use patterns of bits to represent
fundamental functionality, print things, play things, much like those same
scratch blocks.
But no computer scientist really, unless they take out a paper pencil or write a
program or use a website to convert this, can sort of read this and know
going on. That's why we humans are actually going to use not machine code,
is called, the zeros and ones that computers understand.
We are going to start writing source code. And last week, you already wrote
source code, but in the form of dragging and dropping those puzzle pieces.
So this, too, is going to be the paradigm that sort of guides us through
entire semester.
Problem solving programming is really about input.
becoming output.
And we'll focus today then on a certain type of input becoming output.
Someone has to get the source code that's written in a language like C into
machine code, the zeros and ones that the computer actually understands.
So source code today is going to be our input.
Machine code is going to be our output. And we're going to give you today a
special program called a compiler, whose purpose in life is to translate one to
the other. And there's compilers for different languages in the world. We're
going to focus on one that supports today's language, known as C.
And here, as promised, is the programming environment we are going to
tailored to CS50, which is to say we've pre -installed certain software that you
might find useful during the term. But for all intents and purposes, the tool
you will use for CS50's problem set, henceforth, is a very popular industry
standard tool called Visual Studio Code, or VS Code for short.
We are using a cloud -based version of it that lives at literally this URL,
.dev. You can sign into that so long as you have a free GitHub account for which
you signed up, presumably, already. And that will give you access to not only an
industry standard programming environment, but again, an environment
some CS50 -specific things pre -installed.
And at the end of the semester, or even in the middle if you're so inclined, you
can actually download for free VS Code onto your Mac PC.
You can disconnect from the internet, and you can actually program on your own
computer. Caveat, though, is that you tend to hit technical support headaches
the very beginning of the term. So we suggest you do that later in the term
you're already comfortable with this cloud -based environment here.
And here it is. This is what programming shall look like, whether we're using C
now or Python in a few weeks or JavaScript or SQL thereafter.
So here is what is VS Code configured as follows.
At the top right, you'll generally have one or more tabs for code, much like
tabs in a browser. And this is where you'll write code that looks a little
something like this. And in fact, this is exactly the code that you saw a
ago. What VS Code does, among other things, is it actually highlights your
for you. It colorizes it in what's generally
in an illuminating way.
So I did not choose to make this red. I did not choose to make this blue and
this purple. The computer sort of automatically does that for you, as
see, to sort of draw your attention to different ideas in the program itself.
That all happens automatically.
At the bottom here, you're going to use a more advanced interface today onward
known as a command line interface in the form of a terminal window.
So you can still use your mouse or trackpad and click and drag and do
like that in this environment.
Many programmers prefer that it's much more efficient, ultimately, to use your
keyboard more often than the mouse or the trackpad. So we'll introduce you to
that text -based terminal window there.
Up here at top left, you'll have a file explorer.
So what's nice about VS Code is that not only will you have textual commands
with which you'll get comfy, you also have like a normal Mac or PC or phone
nowadays. Like literally files and folders will visually appear to you so
can play with or manipulate them there.
And then lastly, this is sort of like the menu. the so -called activity bar
just has icons for various features, including CS50's duck. So in fact, if
poke around, you'll see ultimately a duck icon when you log in, which is your
own CS50 -specific chat bot of which you can ask questions throughout the
process.
So now that we've got VS Code here, let's go ahead and actually consider
represents. So this is generally, for jargon's sake, a graphical user
which means buttons and icons and menus and all of that. We all take that for
granted on almost any device nowadays.
That's abbreviated, just so you know, as GUI, G -U -I.
But built into VS Code, again, is what not only the terminal window by name,
conceptually, this is a command line interface. So not a graphical user
interface, but a command line interface. interface, whereby there aren't icons
to click on or double click on. Rather, if you want to run a program, you use
the command line interface, or CLI, to type the name of the program that you
want to run.
And so this will feel like a step backwards initially today, because we
of tap and point and double click at things nowadays.
But again, it's going to give us more power, more efficiency, ultimately
this.
So with that said, let's go ahead and actually use it for just a moment.
class, you're welcome to follow along. But suffice it to say, we'll generally
somewhat quickly.
Really, you're going to learn how to program by way of the problem sets each
week. I'll introduce and focus on the concepts, the ideas, the sort of
primitives that will get you started.
But only through actually doing the problem sets is the muscle memory and
practice going to come. So not to worry if it doesn't all sort of go down easily
the first time around.
So here is the code that I claim is equivalent to last week's Hello World
program, let's actually go ahead and do this in the programming environment.
So I'm going to go ahead and switch over to VS Code itself, which is now running
on my Mac here. It's not just a screenshot.
And I'm going to go ahead and do the following to get started with
I'm going to write literally in my terminal window the word code.
And I might have to give it focus by clicking down in that quadrant of the
screen. And then I'm going to give the name of the file that I want to.
And in this case, I'm going to propose that we call it hello .c.
In the world of Scratch, when you downloaded it, you might have noticed
files are all called like SB3 or some such file extension.
When writing code in C, you literally name the file something .c by
But notice some other details, especially if I zoom in.
Everything I've typed thus far is lowercase.
There's no spaces.
And so this is going to be important.
And unfortunately, computers are not forgiving.
And odds are one of the first stupid mistakes you'll do is miscapitalize
something, misspell something, add too many spaces or the like. Not to worry.
time, that kind of muscle memory will come with practice.
So let me zoom out.
Let me now just hit Enter, and you'll see at top right the Code tab that I
promised. So I'm going to go ahead and type out this program pretty quickly,
because I've done it before.
Include standardio .h, int main void, and then some curly braces, as they're
called, and then printf quote unquote hello comma world backslash end close
quote.
All right, so that's a lot, but that too will come in time with practice. But
this is the exact same code that we saw just a moment ago.
Indeed, if I zoom in, it's color coded just as in the screenshot, and thus I
have written my first program.
VS Code will automatically save for you, but you can also hit Control or Command
S to ensure that it's saved. But notice what's happened at top left.
Not only do you see my code over here, you see a visual icon, just like on a
or PC that, yes, this file now exists in your account.
is what you're getting with VS Code for CS50. You're getting your own sort of
server in the cloud.
It's called a container nowadays. So there's some virtual disk space
in the cloud, a la iCloud or Google Drive, that's going to store all of your
files. And at the moment, because I refreshed my account before class, I
have one file in my own account.
What's this? What's this?
Well, this is like my ID number for GitHub.
Not really a big deal. That's just randomly generated by GitHub.
Urban Adventure is the name of my programming environment today, otherwise
as a code space.
This is just a GitHub thing, which is, again, one of these cloud companies.
Instead of choosing random letters and numbers to uniquely identify all of our
programming environments, it's popular in the tech industry nowadays to just
together random English words that sometimes sound kind of cool. But it's
by coincidence, not something I chose. Yours will be different.
All right, so I've written some code.
I created hello .c. I typed in all of that code. I confirmed visually at left
that it was created. I'm going to hide my file explorer, henceforth, just so we
can focus on the code. How do I actually run this program?
Well, on a Mac or PC, we would be in the habit of opening the folder and double
-clicking on it. Or on your phone, you would take it out and tap on an icon.
But not here. Here, we're focusing primarily on the command line interface
within this whole environment.
So I'm actually going to have to introduce a few commands.
You saw already the code command, which for our purposes is VS Code specific,
that just creates a new file called hello .c in this case. But I need two
commands to actually run this program.
The first, nicely, is called make. And then I specify what program I want to
make. And then a little weirdly, I have to type dot slash hello.
But just to take a step back, make hello. If this is about to be my second
command that I type, what does that step represent, perhaps?
given what I said just a minute or so ago.
Perfect. So make represents the compiler, so to speak, the program that
source code to machine code. I have to do that for now manually by running make
hello. Now, make is kind of smart. And even though I'm saying make hello, not
make hello .c, make is smart. And it's going to say, oh, if you want to make a
program called hello, I'm going to assume that there is somewhere in this
a file called hello .c. So you should not type make hello .c. You just type
hello. And then this third command, even more cryptic, what might it do?
If this is step three of three, that's going to run the machine code. It's
to tell the computer in this folder, sort of the dot implies this current
folder, and dot slash just means something in this current folder, run
program called hello.
So that's it. There's three steps to writing a program in C.
You create the file, as with the code command, but there are other ways to do
that too. And you don't even have to use VS Code. You can use dozens of other
alternative programs in the world. You run the compiler, which in this case is
called make.
Little white lie, make is not actually the compiler.
But more on that next week. But make is going to trigger compilation of this
code. And the last step three is to execute or run the program called hello.
So let me go back to VS Code here.
And you'll see that my code is still at the top. My terminal window is at the
bottom. I hid my file explorer, just because it's not that interesting
And I'm going to do what you proposed, which was m -a -k -e space hello, all
lowercase, Enter.
And ironically, thankfully, nothing happened.
And that's actually a good thing in this environment. If nothing seems to
happen, you probably did good. If anything does seem to happen on the
you probably screwed up and you've made some mistakes.
So seeing nothing is generally a good thing.
But what has happened? Well, let me actually go back and open up my file
explorer. And notice there's not only kylo .c, but there's a second file now.
Hello, which is the name of the program.
So hello is the program I want to run.
I'm going to go back to my terminal here. And to run this program, I'm going
do dot slash H -E -L -L -O. I'm going to cross my fingers, as I'll often now do.
And voila, my very first program in C.
How else can we see this file?
Well, down here in my terminal window, let me zoom in, you keep seeing a dollar
sign. That has nothing to do with currency. It's just a weird geeky
that you're prompt at a terminal window. Like, where you type commands generally
starts with a dollar sign. Sometimes it's a hash symbol. Sometimes it's an
angled bracket.
It depends on the system you're on. But dollar sign is very common. It just
means type your commands here.
Well, I've typed code. I've typed make. And I've typed dot slash hello.
But I can type other things, too, and more on these later, like ls.
which doesn't actually spell something, but is short for list, L -I -S -T.
Programmers tend to just be as succinct as they can, so most commands are not
full words. They're often abbreviations. If I hit Enter now, you'll see also two
things. You'll see hello .c, and you'll see in green, just to draw attention to
it, hello as well.
The asterisk here just means, in the programming environment, this program is
executable. You can actually run this by doing dot slash hello. The fact that
this is just white here, that just means it's some text file. It's, in fact,
source code.
So in other words, ls lists the file in my current folder, or you can use your
human eyes in the file explorer at top left and just look at what files exist.
These are one and the same. One is a GUI, one is a CLI, graphical, command
and so forth. And we'll start to take these kinds of paradigms soon for
But let me pause here and see thus far, now that we've written our first of many
C programs, any questions or confusion we can clear up.
So OK, if you don't understand most of the lines of code, that's what today is
about. Yeah?
I don't really understand the difference between hello and hello .c. DAVID J.
What's the difference between hello and hello .c? So hello .c is literally my
source code. It is a file that exists somewhere in the cloud that contains all
of the code I myself wrote.
The hello file is the file that the compiler created for me by converting
source code to the machine code. So inside of hello, theoretically, is a
bunch of zeros and ones.
We can't quite see them.
But if I do this, let me zoom out.
Let me click on Hello and notice that VS Code is going to yell at me. The file
is not displayed in the text editor because it is either binary, that is
and ones, or uses an unsupported text encoding, whatever that means. If I do
open it anyway, but I don't recommend this, like heed these warnings, you
see zeros and ones, but you will see sort of nonsense.
And this is because VS Code is trying to interpret those zeros and ones
incorrectly as ASCII text, like English text, but it's not.
They're instructions for the computer. So as soon as you see scary red stuff
like this, undo, close whatever tab you open, because odds are you can only
break the program you just created. It's not a huge deal. You can recreate it,
but that's what's inside of those files.
Yeah? What if we don't type dot slash hello, we just type hello? DAVID MALAN -
Really good question. What if we don't type dot slash hello, we just type
Well, let me do this. Let me hide my file explorer again, because it's not
interesting here on out.
I'm going to clear my terminal window by hitting Control -L just to be neat and
tidy in class. Or you can literally type clear, and it will clear it. But again,
that's just to keep things tidy. Your TF might do that in section two.
If I just type hello enter, I'm going to get this. Weirdly, bash hello command
not found.
So more on bash down the line. But this just means literally the command hello
is not found because you need to tell the computer where it is.
So dot slash hello means run the hello program that is in fact, right here. By
contrast, you don't run .slash for code, for make, or other commands that we'll
soon see, like ls. Because why? Those are installed in the system for
not just in your individual folder. So that's the difference. Any programs we
write, it'll be .slash something.
All right.
So let's tease apart what is actually going on here and see if we can lean
heavily today on Scratch, especially as the syntax gets weird, perhaps a little
overwhelming, still the same idea.
So this last time, of course, was our Scratch program that just said hello
world. I claim today that this is the nearest equivalent that any programmer
could convert Scratch into C. If we color coded accordingly, indeed, this
of lines up with when green flag clicked is the orange, and then the purple is
just the equivalent of the say block.
So the say block we said earlier was a function.
So let's compare these things side by side, because there's actually some
and reason to what MIT did with Scratch as to why these shapes look like they do
and so forth. So in Scratch, there's a function called say.
Recall that it takes an input, otherwise known as an argument, or a parameter is
another name. And that's always provided in these white ovals, zero or more
white ovals. In C, we've already seen, but let's do it a little more
pedantically, the equivalent of say is essentially the word print.
Why did MIT say you say?
Just because.
It's a little more kid -friendly. But print is the idea in our environment.
It's actually not print. It's printf, because we're going to be able to format
our text in interesting ways. More on that in a moment. But notice, the
parentheses and closing parentheses here sort of conjure up the idea of that
white oval.
So that's kind of intentional on MIT's part.
What, though, in C goes between these parentheses? Well, literally the input
the argument you want to pass to the function, like hello world.
But in C, you have to be a little more pedantic because you don't have a nice
little graphic like this purple block with the white oval. You have to
everything in double quotes.
Those of you with prior programming experience, in C, you need double
not single quotes in this context.
And then there's this arcane detail here, backslash n, which we'll come back
in just a moment.
But that's essentially what's going on. Line by line, from scratch to C, there's
kind of an equality between those two, even though they, of course, look a
little bit different.
Well, let's see what that backslash n is doing, just to highlight some details
here. So let me actually zoom in a little bit here.
And let me go up to my code. And let me just sort of recklessly delete the
backslash n.
I'm going to let it autosave. I'll zoom out. In my terminal window now, I'm
going to run make hello to recompile the code from source code to machine code,
because I changed the source code.
Nothing seems to happen. That's good.
Now I'm going to type dot slash hello, Enter.
And there's a subtle bug since I made that change. What looks wrong to your
eye now?
Yeah, the dollar sign, our so -called prompt, is at the end of the line
of on its new line.
I mean, this isn't really a deal breaker. The code works, and you can
a new command. But it just looks a little stupid. This was not the intent
program. It's sort of good practice to move the prompt to the next line. And
that's because the backslash n is what we're going to call an escape sequence.
So it turns out in programming, you have to tell the computer exactly what you
want it to do. So if you want a new line, the equivalent of hitting Enter on
screen, you have to tell the computer computer to put a new line there.
What you do not do is this. If I zoom out and I go into my code here, and I'll
zoom in on the code, if you want to put a new line, you don't do this.
Why? It's just confusing for the computer. Like, wait a minute, is that a
Did your lines just wrap?
Do you want to put a new line there? It just looks stupid. And it makes it less
line -based, the code itself.
So humans decided years ago, if you want an actual line break, don't just
naively hit the Enter key.
Literally tell the computer, put a new line here.
If you want to move two lines down, just do two of those. If you want three,
just do three of those.
Well, why the backslash? Again, these are what are called escape sequences.
And you don't literally want an N.
let alone nnn, what you want is a new line which is represented in code as
simply backslash n.
Now, for the mathematicians among you, what we're doing now by using functions
like printf is just sort of like f of x notation, if you recall that from high
school or prior, where f is a function, x is an argument or an input thereto.
And we're using parentheses in code just like mathematicians would to write
functions like these.
And the types of functions we're using right now still follow this model.
got input. You want output.
In this case, the input to printf, for instance, just like the say block, is
what's called an argument.
Output, though, of the function printf is what we call a side effect.
And the easiest way to think about that is a side effect is just something that
sort of like happens on the screen.
Visually, audially, it just sort of happens. And there's that effect on the
screen. And we'll contrast this with other types of outputs from functions.
for now, we're focusing on just this, which is reminiscent, of course, of what
we did last week, which is if you type hello world into the white oval, use the
say. Puzzle piece, you get out the side effect of the cat appearing to have
said, hello, world.
Now, as for those escape sequences in C, there's bunches of them, but very few
of them will we actually use in practice.
Backslash n is a new line.
Backslash r is a little more subtle, and it's kind of a feature of yesteryear.
It moves the cursor not to the new line, but to the beginning of the line, kind
of like an old -timey typewriter, if you've seen how those work.
Sometimes, though.
you might want to print out an actual double quote.
But there's a problem, of course. If this is my code here, and I'm already
double quotes as sort of special symbols to surround the text I want printf to
say, it would probably be a little worse. Like, if you wanted to say,
world, with sort of finger quotes, why might this not be a good idea,
if you think about this from the computer's perspective?
Why is this probably not the right way to do this? Yeah.
Yeah, exactly. The computer is indeed going to read your code top to bottom,
left to right. And when it sees the first open quote, OK, that's fine. It
understands that. But when it gets to the second quote, it's going to assume,
oh, wait a minute. Maybe you only want me to say, hello, comma.
And then it's going to keep reading and be like, wait a minute. Why is there the
word world here? And then, wait a minute. Now there's two more quotes.
confusing. It's ambiguous.
And computers need you to be, again, very precise.
So if you want a quotation mark to literally be displayed on the screen,
would escape it, so to speak. speak, which looks a little weird and takes
getting into the habit of. But this just solves that kind of problem.
And similarly, might you use single quotes in other contexts? More on that
And if you really want to bend your mind, how do you actually print a
backslash if you ever care to? It's not that common a character to type. But if
you ever want it on the screen, it seems that we're using backslash as a special
character that says, hey, give me a new line, or give me a carriage return, or
give me a double quote.
Weirdly, in programming, if you want to type a literal backslash, on the screen,
you literally do backslash, backslash. But that's it for sort of weirdness for
now. But this is to say, humans tripped over the same problems years ago. They
came up with solutions.
And now we indeed have these conventions in code.
All right.
So let's tease apart some other features of this in every program we're going to
write, namely what's at the top of this file.
So at the very top of this file, there is this cryptic -looking hash include or
pound include standard IO dot h in angle brackets.
So this is a little weird. We'll talk more about this next week, too. But this
is what's called a header file.
Any file that ends in dot h is not a
Source, well, any file that ends in .h is what we're going to call a header
file. And inside of that header file is functionality that maybe came with the
system, came with the programming language itself.
So for instance, I'm going to do this.
I'm going to go back to my code here, and I'm going to make a very common
mistake that you yourselves might make in the coming days, where I just forget
that line, because I don't even understand it in the first place, so I
didn't think to type it here.
Now, if I go back to my terminal window after clearing it, and I run make hello,
because I want to recompile it, because I've changed the source code, I'm going
to see a fairly cryptic error. I mean, there's more error on the screen than
there is code up here.
But you'll get the hang of sort of reading it to try to figure out what's
on. And I'm seeing this.
Hello .c line 3 character 5.
So that just means line 3 colon character 5 from left to right. It's
visual cue as to where the problem is.
Call to undeclared library function printf with type dot, dot, dot. And then
rest kind of overwhelms me visually at this point.
But that's a hint.
If you do not include that header file at the top of the code you've written,
you do not have access to what's generally called a library.
A library is a collection of code that someone else wrote for you. Maybe it was
MIT. Maybe it was the authors of the C language itself years ago. Maybe it was
CS50 if we wrote some code for you. A library is a collection of code that
someone else wrote for you. And you access it again by including header
that those same people wrote for you.
So if I go back to my code now, let me clear my terminal window just to be Less
overwhelmed. Let me undo what I just did and put that file back.
Can you perhaps infer, just functionally, what is inside of standard
again, someone else wrote?
What must be inside?
Printf. So whoever invented printf decades ago probably put that code in
file. And so by including it, so to speak, in my code, I now have access to
printf functionality.
So that's all. And again, C is lower level than Scratch. It's obviously text
-based, which means you have to be a little more pedantic yourself as to what
you want the computer to do for you. And if you want to use someone else's code,
you indeed have to include it. Scratch didn't bother with this, but we indeed
need to do this in the context of C.
As an aside, just to preempt some unnecessary headache, this word is not
.h. Every year, a non -zero number of people can't understand why their code's
not working because studio .h is not found. It's standard io, s -t -d -i -o
That's one of the first frequently made mistakes otherwise.
All right, so remember that. Let me undo now the unnecessary quotes I added
here. And let me propose that.
We show you where you can learn more. So all of these libraries generally are
documented. People wrote instructions for how to use them. So you don't just
have to listen and pay attention only in class. You don't have to pull up a
book. There tends to be online documentation as well, for instance, for
standard IO header file.
And the documentation in the world of programming for C specifically, are
manual pages, or man pages for short.
Unfortunately, they're really written decades ago for the more comfortable
you, those who have an eye already for programming.
And so what CS50 has done at this URL, manual .cs50 .io, is we essentially have
more user -friendly versions of the documentation for this header file and
others. So for instance, if I pull up manual .cs50 .io, you'll see a web page
like this.
And if I just scroll quickly, you'll see a whole bunch of header files, .h
files, and a whole bunch of functions beneath them. And there's only a couple
dozen or so here. And indeed, per this checkbox at the top, frequently used in
CS50, we have sort of highlighted the functions that odds are over the next
month and a half you will probably want to use.
If I turn off that less comfortable mode, there's actually hundreds of
that come with C. And no programmer knows all of these functions. What they
is they read the manual when they want to find some new piece of functionality.
So I'm going to simplify this. I'm going to scroll down, though, to standardio
.h. for instance, here. And you'll see more functions that we'll eventually get
to. But if I click on printf, you'll see, hopefully, some fairly user
instructions for how this thing works. For instance, under synopsis, you'll see
that we tell you what header file you should include in order to use it.
Below that is something called a prototype.
More on that later.
But below that is a description.
And here is where we, the CS50 staff, have written in layperson's terms
explanations of how this function works, how to use it, and so forth.
But if you'd rather see what the real world uses, you can turn off that mode,
and you'll see much more arcanely the original language.
So in short, these are sort of like training wheels that you can turn on and
at your leisure.
But ultimately, this is real world documentation as well.
So if we want to see something else, for instance, let me go back to the main
menu. And as we'll see today, there are actually function in a header file
called cs50 .h that, for a few weeks, we're going to lean on heavily.
Long story short, it's actually kind of hard. It's annoying in C to get user
input, ironically, to get the human to type in a word or a number.
You have to jump through some technical hoops to make that happen. And we'll
show you how to do it the real way in a few weeks. But for now, among the first
training wheels is a CS50 library code that we wrote that will just make your
life easier.
And indeed, we're going going to give you access to functions that simplify
process of actually getting input from the user. So case in point, we're going
to give you access to a function like getString when you want to get a string
text from the user. String is just text. So if you want to get one character,
one word, one sentence, one paragraph, you can call a function called
We're going to give you another one called getInt when you want to get an
integer from the user, like 1 or 0 or negative 1 or anything else. You can use
that function as well. And we'll see today, too, there's other functions you
use from CS50's library.
In a few weeks' time, we'll take these away once you sort of don't need them
anymore. And you'll see what those library functions have been doing all
for you. But for now, let's focus on this.
perhaps the most useful of them, getString, and solve a problem that we
already pretty easily in Scratch. So recall in Scratch, this was a program
used two functions.
Three, in fact. Ask, to ask a question of the user.
Say, to actually display something on the screen. And join, to combine the
default of Apple banana, or in this case, hello, and whatever the human's
was. So this made our hello program a little more interactive last time. How
we actually translate this into a similar paradigm now? So input and
the story as always. In this case, we have arguments going into those
But now we're going to introduce not side effects, which is stuff that
visually. We're going to revisit that blue circle called answer or the blue
called answer that represented last week what we called a return value.
And this is what many functions will actually do for us. They're not just
to display something presumptuously on the screen or play a sound or a video or
something like that. They're going to hand you back virtually a value.
text or integers or sounds or images that you can then do with what you see
So the paradigm we'll now have is, much like in Scratch, if the input is what's
your name and the function is ask and you get back a return value of answer,
want to actually do this now in C.
So side by side, what code like this in Scratch is going to look like today
onward is this.
Instead of using the ask block, you literally use CS50's function called get
string. It takes input.
So we put the parentheses on the left and the right to kind of conjure the
of this white oval.
Inside of that string, you can put a prompt, so to speak. Like, what do you
the human to be asked in this case?
And I'm missing something still, per the placeholders here. What's missing?
So quotation marks, so literally quotation marks on the left and the
I'm going to be a little anal here. I'm going to put a space at the end because
I don't want to. I could, but I don't want the cursor to go to the next line,
hence no backslash n. If I want the cursor just to sit there kind of
waiting for the user after the question mark, I'm just going to put a space so
it will stay there for me. But this is just an aesthetic detail using the same
idea as before.
So that is the analog of this block.
But how do I get access to the so -called return value?
MIT just plopped it on the screen for me. for us automatically.
In C, we have to write a little more code to get access to that return value.
And the way we do this is on the left -hand side of this line of code, we come
up with a name for the return value.
You can call it anything you want, but answer is a nice equivalent to what MIT
did. You could more generically call it x or y or z, but that's not really
useful. And so computer scientists, unlike mathematicians, will tend to use
variables that are a little more verbose, like the word answer.
But in C, it's, again, a little lower level. You have to tell the computer
type of variable this is going to be.
So I'm kind of conflating variable and return value, but they're being used in
an intertwined way.
The get string function, just like the ask block, returns the value.
If you want to do something with it, you need to put it in something called a
variable, which is denoted in text here.
But again, per last week, the computer doesn't know if it's looking at numbers
or characters or images or sounds. You have to tell it as the programmer that
the zeros and ones that are somehow involved here underneath the computer's
are, in fact, to be treated as text, a .k .a.
string.
Now there's one stupid subtlety still missing from this line of code. Does
anyone know, especially if you've programmed before? OK, all of you have
programmed before. Yes?
semicolon. So one of the headaches of C in a lot of languages is you actually
have to finish your thought explicitly so the computer knows that that line of
code is done. And it's not a period like in English. It's, in fact, a semicolon.
Now, you don't use these everywhere.
We'll see where you use them. But that, too, is a very common mistake to
overlook something simple.
But again, in the coming weeks, even though this might look very cryptic with
muscle memory and practice, you'll start to see these things instantly, even if
for a few days you sort of bang your head against the screen, so to speak.
seeing what the TFs and I much more readily see.
So let's go ahead and do this. Let me go back over to VS Code here.
Let me zoom in just a little bit.
And let me go ahead and do this.
I'm going to get rid of my single use of printf. And I'm going to say the exact
same thing. String answer equals get string quote unquote what's
your name question mark space close quote.
semicolon, and now I want to print out that answer. Well, let me do this
incorrectly deliberately for the moment. Let me just say printf quote unquote
hello answer if I want to plug in answer and I want to add a new line at the end
semicolon. So let me try this.
But there's multiple mistakes now in my code. Let's trip over them deliberately.
Let me go down to my terminal window by clicking at the bottom of the screen.
Let me run make hello again, Enter.
And oh my god, there's even more errors now than there were before. But not a
problem. Let me click on this little triangle here, which is just going to
in on the terminal window so it takes up my full screen.
And just generally, all you have to do is find a few keywords visually that
you a clue as to what's going on. Or as before, you can always ask the CS50
duck. So here's the command I ran, make hello.
Somehow that induced all of these errors. Always read them top to bottom,
bottom up. So from top to bottom, there's a problem on line 5, character
of undeclared identifier string.
Did I mean standard in? No, no, no. I didn't there.
And then also, two errors generated, too many errors remitted.
What did I do wrong?
Well, it turns out what I do need to do at the top of this file, let me click
the triangle to zoom back out.
If I want to use the get string function to get a string, I actually need to
include another header file, which is probably called include CS50 .h.
Technically, any order is fine. I tend to alphabetize because I just know,
therefore, where to look alphabetically for a certain header file.
Now that that's in place, let me again run make hello, enter.
And now we're back in business.
No error message.
So even though you might have more errors than you have code, odds are it's
the computer is confused, and it could be something simple and an easy fix like
that. So just to be clear, standardio .h, because I'm including it, I can use
printf. CS50 .h, I can use get string, because the people who invented C and
people who invented CS50 wrote those two files, so to speak.
respectively. All right, unfortunately, even though the program compiles, that
doesn't mean it's correct.
It just means it's syntactically valid. It's valid C code. If I go ahead and run
dot slash hello and hit Enter now, I'm going to be prompted for my name. So
type it, D -A -V -I -D. And notice there's a space to the right of the
mark, as promised.
Enter. But it just says hello answer, which of course is not the intent. I
wanted to say hello.
David. So how can we do this? Well, in Scratch, it took a couple of puzzle
pieces, but it was pretty straightforward.
If I wanted to say the combination of two phrases, hello and something else, I
joined those two and then passed that output to the input of say.
In C, it's going to be a little different here.
Just because it's an old language and this is how it's done.
Still use printf, because that's the same thing as say.
I got my parentheses. I got my semicolon. Good to go.
But inside of that, this is where printf is different.
If you want to say something followed by something else, in the world of C, you
tend to use placeholders.
So you don't just join things together, as we will do in Python and other
languages. You say to the compiler,
give me the word hello, comma.
and then something else. And the %s means put another string here.
It's sort of like leaving a placeholder in your code or a template where you'll
actually plug in some values.
Now, if this is what I want to display, I still use my quotes as before.
And I might, in fact, have a backslash n if I want to move the cursor to the
next line.
But this is where printf is a little different.
Unlike say, which took one input, Printf is kind of like join. It can take two
or more input if you so choose.
You just have to separate them with a comma.
So much like the join block has two ovals here that are initially white,
and banana, until we dragged and dropped answer on top of it, printf and really
any function in C, if you want to pass in multiple inputs, that's fine. If
they're supported, just separate them with commas. There's no multiple
parentheses. There's no multiple ovals. Just separate them with commas.
And now notice a potential point of confusion.
What's different about this comma and this one, just instinctively?
Sort of minor detail, but important. Yeah?
Inside. DAVID J.
So one is inside, one is outside. So the one that's inside the quotes is
literally the English grammatical comma that you want the human to see. The one
out here is a C thing that's separating the first input to this function printf.
from the second.
Strictly speaking, you don't need a space there. But it's good practice,
stylistically, to separate your arguments with single spaces, just as
there. So let me go ahead and now do something with this. Let me go back to
code here.
I'm going to clear my terminal window, just to get rid of that distraction.
And now I'm going to change answer to %s.
And then outside of the double quotes on line 7, I'm going to do comma, answer.
And then after it autosaves, I'm going to go back to my terminal window.
And just to make another deliberate mistake, dot slash hello, enter.
What's your name? David, enter. It's still broken.
But why?
I still have to recompile it. So again, you just get into the habit. When you
change your code, you have to recompile it so you get new machine code in the
file hello. So let's do it again.
Make hello.
No errors is good.
Dot slash hello, enter. What's your name again?
D -A -V -I -D. And now, hello, comma.
David. So again, a lot of this is still cryptic, but it's going to start to
follow patterns like this. Functions like in math class f of x are written
function name, parentheses, input, comma, input, comma, input, however many
have. They're going to follow these patterns. But notice too, on line six
seven, I have finished each of my thoughts with a semicolon.
So what are the other commands that you can run in your terminal window besides
something like ls? Well, it turns out there's a whole bunch of them. LS, of
course, was simply short for list, which shows you the files in your current
folder. But there's also CD for change directory, which is the command
equivalent of double clicking on a folder to open it up in a graphical
environment. There's CP, which is short for copy, which allows you to make a
copy of a file or folder.
There's Mkdir, M -K -D -I -R, which is short for make directory, which is how
you could make a new folder.
There's MV, which is short for move, which would allow you to move one file
folder. folder from one place to another or simply rename one of those to a
different name. There's rm, which is short for remove, and there's rmdir,
is short for remove directory.
So in fact, let's play around with a couple of these.
Let me go back to VS Code here.
Let me go ahead and open up my file explorer and recall that at this point,
got two files, hello .c, which contains my source code, and then hello, which
contains my machine code, the executable program that I previously generated by
running make.
Well, let me go ahead and propose that I'd like to
prepare to keep all of my files and folders very orderly. So for every
write or for every problem on a problem set I write, maybe I want to store my
relevant files in a specific folder for that problem.
So suppose, then, that I want to put hello .c in a folder, otherwise known as
directory, called hello.
Well, I can't do that quite yet because I already have a program called hello.
So let me use one of those new commands, rm.
space hello will delete or remove hello from my current directory. So I'm going
to hit Enter. I'm going to be prompted to confirm with y for yes or n for no,
remove regular file hello. I'm going to hit y and Enter. And as I hit Enter,
watch the top left of my screen as the hello file would seem to disappear.
Voila, it's now gone.
So now I'm going to go ahead and use a different command. Let me go ahead and
mkdir for make directory.
I'm going to call the directory itself hello. And watch again at top left what
happens. Enter.
Now I have not a file, but a folder called hello. And in this GUI, the fact
it's a folder is indicated, one, by its icon, and two, by that little right
-facing triangle, which means I can expand it to see what's inside.
And in fact, if I do that, I'll see, of course, that nothing's in it, because we
literally just created it.
All right, well, what if I want to move?
Hello .c into the new Hello folder. Well, I could, just like on Mac OS or
Windows. I could actually, in my file explorer, click and drag one into the
other. But let's do this entirely within the terminal window.
So let me do this. Let me move, or MV for short, my file called Hello .c into
new destination folder.
And I can optionally put a slash at the end of hello just to make super clear
that it's a directory, but that's not strictly necessary.
But if I say mv hello .c hello with spaces in between, assuming hello exists
a folder, watch what happens at top left now. It's a little more subtle, but
hello .c is going to move inside of the hello folder right now.
And indeed, it's only slightly more indented. But notice if I collapse the
folder, notice that it seems to be gone because hello .c is now inside of that
folder. Of course, if I expand that, I'll see it again. If I go back to my
terminal window and type ls for list, now I don't see Hello .c. And I don't
an executable program anymore, but I do see hello. And the slash there just
makes super clear to me, the user, that it's indeed a folder.
So how do I change into that folder?
Well, I can obviously use the graphical interface at left and click and expand
and sort of see what's going on. But there's no direct connection between the
file explorer at top left and my terminal window at bottom right. Rather,
are just two different ways to explore the underlying system.
So if I want to change my terminal window into this new directory, I can do
for change directory, hello, and then enter. And now notice my terminal
prompt changes slightly.
There's still a dollar sign, which indicates type my commands here.
But before that dollar sign, just so that I have a reminder, sort of
that visually remind me what folder I am now in, I see that I'm inside of hello.
If I now type ls, I should see the file I expect to be in there, which is indeed
hello .c.
Now, suppose I want to try out some of those other commands. And suppose I want
to maybe rename this file. I really want this file to be called something else.
So maybe I might do something like this, mv hello .c space, and now a new name
for the file.
Well, maybe I want to save this as an old version of my code, because I wanted
to start fresh with something new. So I could do something like this, mv hello
.c old .c.
And watch what happens at top left.
Hello .c, of course, gets renamed via the move command.
So I can use move to move a file into a folder, or I can use it to rename a file
or folder, as I've just done here.
Now, suppose I want to undo that. Well, I can't just type undo. I can't just hit
Control -C, but I can do the opposite, in effect.
mv old .c hello .c will now, per top left, Change it back into that file.
If I want to make a copy of this file, maybe as an actual backup, because I'm
really happy with this version and I'm worried about breaking it, well, I could
do cp for short. I can then do hello .c. And then I can do something like backup
.c or any other file name. I'm taking care to use the same file extension so
that if I do open this file later, it still opens and gets highlighted and
colorized in the same way. But watch what happens now at top left when I type
Enter. I now have two files in this hello folder. And indeed, if I type ls
I can see exactly the same.
So long story short, there's this whole list of commands, and even more than
these, that allow you to manipulate the underlying system in exactly the same
way that you and I have probably done for years by using a mouse and pointing
and clicking and double clicking.
But for now, let's undo all of this, because I haven't really written that
programs today. And I'm going to keep things simple today and keep everything
my same folder. So let's undo all of this.
Let me go ahead and now remove backup .c, because I don't particularly care
about that. I'm going to be prompted to confirm as much. Then let me go ahead
and move hello .c out of this folder and into the original folder. And
conceptually, the original folder is what we would call the parent folder,
folder that contains this hello folder.
And the way you can specify the parent folder, like back up from once you came,
is with .dot. So a single dot, as we've actually seen, .slash hello, .slash a
.out means execute a program in this directory, dot. But .dot refers to to
parent directory.
So watch what happens at top left when I move this hello .c file out of this
folder.
shifts a little bit to the left to indicate that it's no longer in that
I'm going to go ahead and type cd dot dot, which will bring me back to my
folder. Or even more useful, especially if you get confused or lost somewhere
within your folders, you can actually just type cd and nothing, and that will
whisk you back to that original folder no matter where you are. So it's a nice
shortcut, and it's a nice way of undoing any confusion you might have caused for
yourself. Lastly, let's go ahead and get rid of the hello.
directory with rm dir hello enter.
And that now disappears at top left as well. Now, what I was hinting at here,
whereby I had my hello .c file in a folder and I was moving things around
renaming things and backing things up isn't strictly necessary because there's
actually other features still inside of VS Code that you're welcome and
encouraged to play around with. In fact, if I go to my so -called timeline at
the bottom of my file explorer here, you can actually see that there's been
automatic backups made over time of this file. So if you click, click, click
through those backups, you can actually see different versions of the same file
slightly in the past, which might save you the trouble. of having to manually
create files.
And in fact, in the world of software development in industry, there's
standard tools very similar in spirit to what we've been using GitHub for that
allow you manually to make different versions of your code so that you can
proactively keep track of all the changes you've made without manually
things as you might typically on your own Mac or PC.
All right, let me clear my terminal window and ask if there are any
Yes, over here.
DAVID J. Yeah, a really good question. If we had something other than a string
of text, and we had an integer, would you still use %s? No, you would use
something else. And indeed, %i is what we're going to use, and we're going to
actually do that.
Perfect segue to other types that C actually has.
So up until now, we've been calling a string of text literally a string. And
this is common in many programming languages, including Python and
Strings in the programming world just mean text.
whether it's zero or more characters thereof. But C does have other data
just a few of which we'll dabble with today, but you'll use more over time.
We've already seen string, for instance, which is indeed a string of text. But
let's focus as well on an integer.
As an aside, there's other types, too. There's Boolean values, like true or
false. There's chars, which are single characters instead of full phrases or
sentences. There's doubles and floats, which are real numbers, something with a
decimal point, the equivalent of fractions.
And there's longs. which are integers, but longer integers, even bigger
than you might type by default. So let's focus on ints, because so many computer
programs, of course, manipulate numbers in some way. So what can we do with
this? Well, if we want to be able to get an integer, lucky enough, CS50's
library comes not just with get string, but also get int. So that's going to be
a third function we now use in C.
And we need to know what are generally called format codes. So that placeholder
I called before %s is indeed for a string. If we want to place an integer
of something we're printing to the screen, We are, in fact, going to use %i
instead. So let's now actually use these building blocks, get int and %i, to
actually get numbers in some way to sort of solve a problem.
Well, what problem could we solve? Let's introduce another concept from scratch
and programming more generally known as conditionals, like those proverbial
forks in the road. If something is true, do this.
Else, maybe do this other thing. So in Scratch, we might have had a set of
puzzle pieces that looked like this. If x is less than y, then say, or have the
cat say, x is less than y.
So it's sort of a stupid program, but it just demonstrates how we have two
variables, x and y, in the context of Scratch. We're comparing them with a
Boolean expression.
We're using a conditional to then conditionally say or not say this phrase
depending on whether this question has the answer of true or false, yes or no.
In C, it doesn't look all that different. It's a little more cryptic,
say literally if.
You use parentheses, similar to functions, but confusingly, by
put a space after the word if. So you don't put spaces after function names.
do put spaces after words like if. And you use the parentheses to conjure up
this weird trapezoidal -like shape. So there's no real keys that kind of
that. So C uses parentheses, like most languages.
And then there's these weird curly braces, which, at least in English, we
use all that often. But they're there on your keyboard, English or otherwise.
And they essentially allow us to create this sort hugging shape to the puzzle
piece. Anything inside of those curly braces is going to be equivalent to
anything inside of this yellow hug that's sort of grabbing one or more
inside. So what do we put inside?
Well, this part is straightforward.
Printf, quote unquote, x is less than y, backslash n, semicolon. So nothing new
here. The only bit of new code is this if construct instead.
What if you have an if else, so a two -way fork in the road? This is what that
looked like in Scratch.
Same question. If x is less than y, then say x is less than y. Else, say x is
not less than y.
In C, the code is going to be set up initially like this. So two sets of
braces to represent this pair of yellow bars and this pair of yellow bars.
And what's inside of them, indented no less, just like our pseudocode last
is two printfs. x is less than y.
x is not less than y.
So that's it. So the only new stuff here, really, is now the else.
keyword, which does not need parentheses, because you're just saying,
this other thing.
But what if it's a three -way fork in the road? And we'll stop after that.
Here's a three -way fork in the road in Scratch. If x is less than y, then say
this. Else if x is greater than y, say this.
Else if x equals y, then say this.
So this is a little more precise, because now we're handling equality, not
greater than or the opposite.
In C, it's going to look similar to before, but we're adding this element
And at first glance, especially if you've never programmed before, it looks
I'm an idiot and I made a typo.
What looks wrong?
There's like two equal signs, like not a typo. So it turns out Recall from
earlier, when we used the equal sign the first time around, we used it in the
context of getting a return value back from a function, like the get string
function handed me back the user's answer.
So unfortunately, because humans decades ago decided, hey, let's use the equal
sign to assign a return value from the right -hand side of a line of code to
left -hand side, we sort of painted ourselves into a corner and were like,
shoot. What do we do when we actually want to test for equality of two values
the left? left and right. So what most languages, including C, do is use double
equal signs. So you can say double equals or equals equals or whatever, but
is, in fact, syntactically correct.
What's inside of these three sets of curly braces?
Same idea, printf, printf, printf, based on what English phrase you want to
print out.
So this code, both in Scratch and C, I'll claim is correct.
It won't run because we still need the other stuff, the equivalent of the when
green flag clicked. But out of context, this code is correct.
But there's a subtle weakness in design.
And we'll talk a lot about this this week and beyond. Correctness just means
code does what it's supposed to do.
Design is more subjective, like how well have you written your arguments in an
English paper? How well have you written your code is design.
This code is not designed as well as it could be, because I'm doing more work
than I need to.
Yeah, and back.
Yeah, I don't need the x equals equals y, but why, logically?
Exactly. That's just a math thing. Like either x is less than y.
Or it's greater than y. Or the third and final option is they must be equal.
So it's subtle.
But why would you bother wasting time writing a line of code and expecting the
computer to run a line of code that is just going to answer a question that
logically you could have concluded already?
Because if x is not less than y and x is not greater than y, then my god, just
print out x is equal to y because you know at that point logically it's true.
You don't need to waste your time or the computer's asking a third question
unnecessarily. In reality, it's not a huge deal. No one's going to notice in
real world on a Mac or PC that there's this extra line of code. But it's a bad
habit. Keep it simple. Don't write code that doesn't need to be there if
logically you can conclude otherwise. So in fact, let's clean this up both in
Scratch and in C. I can tighten this up, so to speak, use less code here, less
code here.
And honestly, if only statistically, the less code I write, the less likely I am
going to make mistakes.
So that too is probably a net positive.
overall. Writing less code is generally better than writing more code, not
unlike English essays, too, perhaps.
All right, questions about this feature of C, conditionals, and this syntax?
Yeah.
Oh, a really good question. And yes, jumping the gun, there are alternative
to solve problems like these. And the question was to summarize when to use
else, if, else versus what's called a switch statement. More on those another
time. But this is going to be true in general in programming, not just C, not
just in Scratch, but every language.
There are going to be several.
dozens, hundreds, an infinite number of ways to solve problems. Among the things
we're going to teach you, though, is indeed how to do things well or better
you might otherwise.
And we're going to introduce you eventually to another feature of the
that can even simplify this code too.
So for now, let's actually use this then. So let me go over to VS Code
I'm going to go ahead now and clear my terminal window.
Down here, I'm going to go ahead and close the hello .c tab, just so that
going to create a new program. And let's just do something a little simple using
some operator, so to speak. And I haven't used this word by name, but it
out that there's lots of operators that come with C, just like a lot of
operators that came with Scratch for doing assignments or less than or less
or equal to, greater than, greater than or equal to, actually equal to, not
equal to. Now, some of these are a little cryptic, but There's no easily
key on your US English keyboard, at least, where you can do less than or
or greater than or equals. So what most programming languages do is you don't
use a special symbol where there's an angle bracket and then a line below it.
You actually just use two characters.
So greater than or equal is literally this this. Less than or equal is
this this. We already saw that equals is this this.
And not equals is to use an exclamation point. So this, too, is a thing in
programming. Using the exclamation point, pronounced bang, is how you
logically certain things. So bang equals or not equals is how you would express
exactly that idea.
It's just a symbol on the keyboard that some human decided, let's use this one
to invert the idea.
But we're going to need one other thing for this program, specifically
variables, which we've used already sort of because in Scratch we got one for
free. We had that answer variable that stored the return value of the ask
But let's consider in general how you can, and probably did for problem set 0,
use a variable of your own, like keeping track of a counter or a score or the
like. In Scratch, if you want to create a variable called counter, you can set
it equal to some initial value like 0.
In C, that code's going to look similar.
You literally just write whatever name you want to give the variable, then an
equal sign, and then the value you want to give that variable.
And because the equal sign is the assignment operator, it will behave
essentially right to left and copy the 0 into counter.
But this isn't enough for C.
Remember that you, the programmer, have to tell the computer, is this indeed a
number? Is it a letter? Is it an image? Is it a sound?
You have to tell the computer that this is an integer.
otherwise written as int for short in C.
But there's one other stupid detail that's missing, which is now semicolon
finish the thought here.
But this, then, is equivalent to this in Scratch. Let's do another. In Scratch,
if you wanted to increment the counter, that is, add 1 to it, you could
literally use this puzzle piece here and specify you want to add 1.
In C, it's going to look like this.
Counter equals counter plus 1 semicolon. Now, at a glance, this seems like a
paradox of sorts. Like, how can counter equal counter plus 1.
I can't make that math expression true, but it's not math in this case. The
single equal sign is assignment.
So this means take the current value of counter, whatever it is, add 1 to it,
and then copy that value from right to left into the same variable, thereby
changing it from 1 to 2, 2 to 3, and so forth.
This, though, is so common in programming, to be able to increment or
decrement numbers by 1 or 2 or more, is that you can tighten it like this.
This is the exact same thing, a little faster to type, saves you keystrokes,
maybe less chance for error.
Counter plus equals one semicolon is the exact same idea.
Better still, this is so common in C and C++ and Java that there's a third way
to do this. To my comment earlier about solving problems in different ways, the
most canonical, the most popular way is probably just to say counter plus plus
semicolon, which literally automatically adds one semicolon.
to that value. Only works for one. If you want to do two or three or some
increment, you have to use one of the other approaches.
But this simply does the same thing as this.
And if you want to invert it to negative 1, you change the plus plus to a minus
minus instead.
So again, just little things that we'll see and pick up over time.
Invariably, you'll have to look them up or check the notes or look back at the
lecture slides.
But in time, this will get familiar if you are not already familiar.
So let's consider just logically.
how we might implement this in code. Let's go back to VS Code here. And let
propose that we create a program called compare .c, whose purpose in life is
just to compare a couple of values.
I'm going to go ahead and proactively, based on the previous chat, include
CS50's library from the get go. I'm going to include standardio .h from the
go, so I can use get int and printf respectively.
I'm going to just on face type int main void.
And today, we won't explain what that does. More on that to come. For now,
assume it's like when green flag clicked.
But in this program, let's do a couple of things. Let's declare an integer
called x and assign it the return value of get int. And let's just keep it
simple. Let's ask the user not what's their name, but what's x, question mark,
semicolon. Now, so that we have something to compare, let's do it again,
with y.
int y equals get int, quote unquote, what's y, question mark. And I'm
again, a space just visually so the cursor nudges over a bit, followed by a
semicolon. At this point in the story, my users will be prompted for x and y,
respectively. Let's do something with those values. How about if x is less
y, then go ahead and print out, quote unquote, x is less than y,
backslash n, close quote, semicolon.
All right, and let me hide my terminal window for just a moment. This is a 13
-line program at the moment, but really it's like five or six interesting lines.
The rest has been copy -paste from previous programs.
Notice a few details.
One, I've indeed used my curly braces here.
And notice if you highlight lines, you'll actually see little dots that can
you make sure, oh, there are indeed four spaces there.
I've been indenting, just like we did last week with pseudocode.
Strictly speaking, it's not necessary, but it's going to be way easier to read
your code if you do add all of this white space, so to speak, than if you
and then submit to us as homework a program that looks sort of god awful
this, which is to make it much more much harder for the human to read it, for
you to read it, your colleagues in the real world to read it. But the computer
is actually not going to care. In fact, as an aside, one of the tools we have
built into VS Code for CS50 is this button at top called Style 50.
This is a program that we indeed wrote that will give you suggestions on how to
improve the style of your code so it looks like the right way that
would generally write it. As an aside, The computer world is fraught with
religious debate, so to speak, as to what code should look like. And people
the real world will have really stupid arguments over how many spaces to use
indentation and what lines code should go on and so forth.
Generally, in the real world or in a class, there's an official style guide
someone sort of autocratically declares, this is how everyone should write their
code, so that just everyone's code in the company or course looks the same.
you'll find in the real world,
reasonable people will disagree.
When you click style 50, it will be formatted as we ourselves recommend in
And in fact, let me zoom out here.
And this looks a little cryptic at first glance, but on the left is the code
that I just wrote and made a mess of by deleting all that white space.
On the right is the way the code should look if it is well styled.
So whereas correctness is all about does the code work the way it's supposed to,
design is about how well have you written that code?
Is it efficient?
Did you make good decisions?
Style is purely aesthetic.
Is it readable?
Does it follow a standard?
Can another human sort of easily skim it top to bottom, left to right, and
understand what's going on? So these green highlights are saying, please add
white space there.
And so I can actually change my code to match.
On the left -hand side here, if I realize, oh, my code's looking pretty
watch on line six at left as I hit the space bar to, whoops, sorry, on the
1, 2, 3, 4.
Notice that the right -hand side is starting to be happier with my code by
getting rid of the green indicators.
And I can do 1, 2, 3, 4.
That fixed that. Over here, I can do 1, 2, 3, 4.
I can move this onto its own line by hitting Enter.
And you know what? If it's taking too long, once you get into the habit of
things, you can just apply changes. It will give you the suggestions
automatically, and we're done and on our way. But for practice's sake, I would
get into the habit of doing things manually until it gets boring and
which point you might as well automate the process with a single click.
All right. So let's actually run this code. I'm going to go ahead and open my
terminal window again and clear it for clarity.
I'm going to run make.
Compare and hope that I didn't make any mistake.
I don't seem to have yet.
Dot slash compare.
And now notice I'm prompted. For x, let's type 1.
For y, let's type 2.
Enter. And x is less than y.
Let's do a little sanity check, so to speak. Let's rerun it. Dot slash
What's x? Let's do 2 this time.
1 for y.
And this time it said nothing.
So that's to be expected, because I didn't have a two -way or a three -way
in the road. The only time this code should say anything is if indeed x is
than y.
So for those of you who might be more visual when it comes to learning, here's
flow chart that represents this same exact program.
If you read it top to bottom.
You start the program with dot slash compare.
You are then prompted for x and y, and you're asked this. Is x less than y?
And the fact that this is a diamond means this is a Boolean expression, a
question that the computer is asking itself.
If the answer to that question is true, then quote unquote x is less than y gets
printed, and the program stops.
Else, if x is not less than y, as in the second scenario, the answer is, of
course, false, and nothing more happens.
But we can build out this tree, so to speak, by adding a bit more code. So
make it look like the second Scratch example.
If I go back here, it's not hard to just say, else if x is not less than y,
let's say that.
x is not less than y, backslash n, close quote, semicolon.
Let me now go ahead and rerun, make, compare, enter, dot slash compare,
And again, I'll do the second example, 2, which is bigger, and 1, which is
smaller. And this time, I will see.
x is not less than y.
If then we were to look not at this flow chart, but a slightly bigger one, you
can sort of visualize it this way. Everything in the left -hand side of
picture is the same.
But if it's not true that x is less than y, the answer is thus false. This time
we say, quote unquote, x is not less than y.
And we can do this, obviously, one final time just to bring the point home. If I
go back to my code.
And I even more pedantically compare these three values.
Let me go ahead and do this.
So else, I don't want an else, actually. So let's go ahead and do this.
Else if x is greater than y, let's then say x is greater than y
in English. And then finally have an else that says printf x is equal
to y.
close quote, or rather, backslash n, close quote, semicolon. So just to show
this all on the screen at once, this is identical now to that Scratch version.
It's well -designed, because I'm not asking the equals equals question
unnecessarily. If I go back to my terminal window here, clear the screen,
make compare, Enter, and then dot slash compare again, Enter.
What's x? Let's do 1.
Let's do 2.
x is less than y. Let's run it again.
Dot slash compare.
What's 2?
And 1, x is greater than y. Once more time, dot slash compare.
What's x1?
What's y1?
And now x is equal to y.
As an aside, if I seem to be typing fairly fast, you can actually kind of
with your keyboard. If you go up or down, you can scroll through all of the
commands that you've typed. So it's actually.
Excuse me, very useful. If you just hit up, it will pre -write the previous
command for you, at which point you can just say enter.
Or there's other fancy features built into this programming environment.
If you do dot slash S -C -O -M and then get kind of bored with typing out the
whole English word, you can hit tab for tab completion, like in a web browser,
and it, too, will autocomplete if it finds a file that starts with those
letters. A little efficiencies here.
Questions, then?
On the code here. Yeah.
I have a question about libraries.
Sure. Is there any downside to just putting in all of the libraries?
A good question. Is there any downside to just putting in all of the libraries?
Like we saw in the manual pages a moment ago, performance.
So generally speaking, C is meant to be a very efficient language, so much so
that even though it's decades old, it's still used omnipresently nowadays
because it's so fast.
It therefore minimizes time. It minimizes energy use. So it's still
heavily. you would slow things down if you told the compiler, by the way, give
me all of these other functions that I'm never going to use.
So in short, just don't do that because it's unnecessary.
But a good question.
Other questions on what we've done here?
Yeah, in front.
Just a follow -up.
What is it?
A YSC faster?
A YSC faster than other languages? Let me answer that in more detail in week
when you'll see.
how much easier it is to write code in other languages because someone else is
doing a lot of the work for you. So as an introductory course, we're sort of
teaching you bottom up, like how do you write code? How does the computer
understand code?
Eventually, this kind of stuff, certainly after like five, six weeks of
it's going to get tedious doing some of these things.
We're going to switch to another language that takes away the tedium and
us to really focus on the problems to be solved once we've sort of graduated to
that point.
Yeah?
Sure, to repeat the keyboard shortcuts, you can just go up, up, up, up, up, and
that will go through all of your previous commands, at which point you
hit Enter.
Or you can use tab completion. So you can start typing a word like code, and C
-O -D tab will finish the thought, or dot slash C -O -M tab will finish that
thought, just to save yourself some keystrokes. And clearing the screen is
Control -L, which has no functional purpose other than keeping things neat
tidy in class.
So a design question.
So this code, I dare say, is correct. Let me zoom in a little bit here.
Let me change the code to just do this, even though we already saw from scratch
that we probably shouldn't do this.
Why should we not do this?
If, especially, I'm just more comfortable asking three separate
if x is less than y, if x is greater than y, if x equals y, do this. It's a
world to live in. Just ask your questions. You don't have to worry about
else, if, else, if, forks in the road. You can just ask three questions. But
let's put a finger on why is this correct, yes, but not well -designed.
Yeah, and back again.
OK, so there could be cases that are potentially outside of these three.
this is relatively simple math comparing numbers, we don't have to worry about
that here. But yes, in general, you might miss a scenario without using a
-all like else.
Yeah, so maybe more than one of them could be evaluated as true. Not going to
happen here, but yes, you could accidentally create a situation where
print or three things print because you didn't really think about the boundaries
among these questions that you're asking. Again, not applicable here, but
general, a good concern.
DAVID J. Really good. Really what's concerning here in this example is
slowing the computer down by wasting its time having it do work that is
logically unnecessary, even more so than the scratch in the first C example.
Why? Suppose that I type in 1 for x and 1 for y.
Because I wrote this code top to bottom, this question is going to be asked no
matter what.
The answer is going to be false.
This question is going to be asked no matter what. The answer is going to be
false. This question is going to be asked, and no matter what, the answer is
going to be true. We're OK there because we had to ask all three questions.
But suppose I did the first thing. x is 1, y is 2.
Then this first question is going to be true because x is 1. is less than y, 1
is less than 2, so this is going to print.
And yet then I'm wasting everyone's time asking, is x greater than y? Even
though it obviously isn't. Is x equal to y?
It obviously isn't. You're doing three times as much work in that particular
case. It's just not good design.
And again, for those of you who think a little more visually, we can actually
make this picture.
To match, here is a final flowchart for bad code, bad design.
Why? Because no matter what, when you start the program and you want to stop
program, you're going through all three of those darn questions no matter what.
Whereas the previous flowchart got us to the stop.
Bubble faster by taking alternative arrows based on true or false answers.
short, still correct, but bad design.
And so again, even for problem set one, when we start writing C code, consider
not just getting the job done, but how you might get the job done better than
you might otherwise.
All right, let's add a few other features into the mix.
Here we have those same data types that are supported by C. Let's focus for a
moment on something a little simpler, just chars, single characters.
Unfortunately, for better or for worse in C, the language makes a distinction
between strings of text, which are generally words, phrases.
They can confusingly be single characters or even zero characters if
type anything in between the quotes, but more on that another time. But when you
know from the get -go that you only want to get a a single character back from
the user, like y for yes, n for no, for instance, which is super common in
programs, you can get that using a char, and CS50's own function, getChar.
So how might we use this? Well, let's go back to VS Code here. I'm going to
close compare .c. And let's write a third program altogether.
Let's call this one agree .c.
And this is meant to represent terms and conditions where you have to check a
box, yes or no, or something like that.
In this program, I'm going to go ahead and do the following.
I'm going to go ahead and, as before, include CS50 .h so we've got it, include
standardio .h so that we've got it.
Int main void, because we have to do that for now. More on that another time.
And now let's ask the user a question. Do they agree?
So I'm going to call get char and then pass in a prompt of do you agree
mark with a space.
semicolon. But as before, with get string and get int, those functions
value. So I want to assign that value from right to left to a variable, which
could call answer again. But honestly, this program's so short, I'm just going
to use the letter c, which is conventional.
So c for char, i for int, or n for number are very common. But one more
what's still missing for my variable here?
I need to say this shall be a char, not an int, not a string, a single char.
All right, now what do I want to do? I can ask a question. If c equals equals
lowercase y, then go ahead and print out, just so we see something on the
screen, agreed period backslash n, as though they agreed to the terms and
conditions. Else, if c equals equals lowercase n, go ahead and print out, for
instance, not agreed, just so we see something.
on the screen.
So let me hide my terminal window and focus on the code. There's a couple of
details here that are a little interesting.
So one, what did I do on line 7 and 11 that is not consistent with what I've
done before?
Subtle.
So I'm using apostrophes or single quotes now instead of double quotes.
It's a C thing. When you're using strings, you use double quotes. When you
single chars, You use single quotes.
So the argument to get char, that's still a string. It's a whole sentence
I'm passing in. So that is just like get in, just like get string.
But when I get the answer back, the return value, and put it in this
and I want to check what is that one char, I have to surround the char I'm
comparing against in single quotes or apostrophes, both for the y and for the
So this program is not super well designed, because it's not going to
uppercase. It's not going to handle weird inputs very well. But let me open
terminal window, make agree, Enter.
The code compiles OK, dot slash agree.
Do I agree? Let's try it. Y for yes.
OK. Let's try it again.
Dot slash agree.
N for no.
Not agreed. Let's do it one more time. Let's very enthusiastically say yes in
all caps.
And it just kind of ignores me.
But why?
Well, this is a feature of CS50's get char function.
If you tell us you want to get a char, we're not going to tolerate a whole
string of text from the user. We're going to prompt them again and again and
again until they give us just one char.
So yes is three times too long. So let's actually just do a single capital Y and
see what happens. Return.
The program ignores me altogether.
So all right, this is kind of a poorly designed program. It's a little annoying
that we'll just ignore humans, even if they type in y or n. That just happens
be uppercase. So let's improve this. Let me go ahead and add a couple more
conditions. Else if c equals equals uppercase y, then go ahead and print out
agreed, same as before.
And then down here, else if c equals equals capital N, then let's go ahead
print out again not Agreed. So this is now more correct.
It's still going to ignore bogus input that makes no sense if it's just like
word, if it's a different letter altogether.
But this to code, while correct in some sense, is still poorly designed.
Even if you've never programmed before, what rubs you the wrong way about this
code now?
Be critical. Yeah?
Yeah, it'd be nice to just merge the lowercase and the uppercase Y together.
The same thing for the lowercase and the uppercase N. Why?
If only because literally lines 9 and 12 are identical.
Lines 17 and 21 are identical.
And while not a huge deal, if I go in and I change this sentence, odds are,
the course of my lifetime programming, I'm going to forget to change this one,
even though I changed this one. Or I'm going to forget to change this one and
this one. So you don't want the code to get out of sync, potentially.
to repeat yourself.
So don't repeat yourself is a tenet of programming, too. If you can avoid that
by somehow factoring out some commonality, you should do so, similar
to math, when you factor out variables or the like.
So let me tighten this up, so to speak. Let me get rid of what we just did so
that it's a little shorter as before.
And let me express myself with two conditions using the following syntax.
I want to check if c equals equals lowercase y or C equals equals uppercase
So you can actually use what's called a logical operator, two vertical bars,
which means or, and we can do this down here, or C equals equals capital
N. So same exact functionality, but to your point, we've now eliminated what,
like another one?
It was like, what, one, four? It's like eight lines of code now are gone, which
is eight fewer lines that I might screw up in this program, less opportunity for
mistakes or bugs.
Probably a good thing. So now if I run this, let me open my terminal window.
Let me run make agree, enter, dot slash agree, enter. Do I agree?
Capital Y.
Now it seems to be handling both of those situations.
So just a little tighter. As an aside, we won't use it here. But if you want to
say and, which would be nonsensical, it, a little confusingly, is 2 ampersand,
means a logical.
and whereby the left thing has to be true and the right thing has to be true.
it's two Boolean expressions at once.
This one makes no logical sense, though, because the character cannot be
simultaneously lowercase and uppercase. It's got to be one or the other. So two
vertical bars is logically correct. That represents our notion here of or.
Question?
No?
Yeah.
You could not write or. So I'm saying or just because that's a little more
normal, but this is incorrect.
However, sneak preview, in the language of Python, you actually will literally
say or among other things, which gets a little more user -friendly.
Other questions on this here?
Searching? Yes, in back.
Is there an easier way to handle case sensitivity?
Yes, and we'll show you that next week, in fact. So we can combine this code to
be even tighter.
All right, let's do one final set of examples before taking a cookie break,
we could. But let's go ahead and close agree .c here.
Let me open my terminal window. And let's go ahead and implement a sort of
virtual cat, as we did last week. I'm going to code up a file called cat .c.
I'm going to implement this in a few different ways, the first of them pretty
foolish. So here, I'm going to include standardio .h. No need for CS50 just
int main void.
Inside of these curly braces, let's go ahead and do printf meow to get the cat
to meow.
And then to save time, I'm going to copy paste that two more times. So this cat
shall meow three times in total.
All right. I'm going to go ahead and make the cat, so to speak. All good.
Dot slash cat. Enter. And it meows three times, just like our scratch cat last
time. I'll stipulate this is correct.
This is a really well implemented cat, correctness wise.
But why is it bad design intuitively?
Just like last week.
I keep repeating the code. I mean, I literally copied and pasted, which is
of your first obvious sign I'm probably doing something wrong if I'm copying and
pasting, because I'm literally repeating myself.
So to spoil it, like odds are a loop is probably going to be our friend here.
And so in fact, in C, we have those features as well.
So in the world of C, we can implement some of last week's same ideas in a few
different ways.
These are a little more mechanical, but suppose we want to repeat something
literally three times.
Scratch gives us a repeat.
A block with an input, so easy.
C, in a lot of languages, is going to be a little more mechanical. And it's
going to look ugly at first. It will take some getting used to. But it is a
paradigm you will use again and again and again. This will become very rote
memory before long. Well, the most direct translation of this scratch code
is probably something that looks a little something like this, whereby I
initialize a variable, here called i, and set it equal to 3. That's the code
equivalent in C of putting up three fingers.
Then what I want to do is while i is greater than 0, that is to say, while I
have at least one finger up, go ahead and do the following. And then once I've
done that, for instance, say meow on the screen, I want to go ahead and
decrement i.
and then do this whole thing again.
Now, I could have called this variable counter for consistency with earlier.
But it turns out it's conventional. When you've only got one variable involved
in your code and all it's doing is something simple like counting, you can
ahead and call the variable i for integer, for instance. But it would not
wrong to instead call i counter.
But notice, too, that in this so -called while loop, as we'll start to call it,
there is this parenthetical. And that parenthetical is actually itself a
expression. But unlike an if statement, whereby the Boolean an expression is
evaluated just once, and if the answer is true or yes, you do that thing.
The Boolean expression in a while loop here in C is evaluated again and again
and again every time you go through the loop to check if you should keep going
through the loop. So for instance, if the goal at hand is to say meow, well,
course, the comparable C function is going to be printf. And I want to print
on the screen meow, followed by a new line. Well, what's going on? Well,
I initialize i to 3.
I then check, is i greater than 0?
And of course it is, because effectively in the computer's memory,
I decrement i, which means to put down one of those fingers, and then.
I check the Boolean expression again. Is 2 greater than 0? Of course it is. So I
print out meow. And then I decrement i, putting down one more finger. Then I
check the expression again. Is 1 greater than 0? Of course it is. I print out
meow. And then I decrement i. And now I'm down to 0.
I check again.
Is 0 greater than 0?
Well, no.
And so the loop will automatically, by the definition of how this C code works,
terminate for me and proceed to any other lines if there are more lines of
that I've written.
So how do we actually implement this then in code and get it running, well,
going to be pretty much the same idea. Let me go back to VS Code here. I'm
to get rid of all of this copy paste. And inside of my main function, I'm
to do exactly what we saw.
Int i equals 3.
semicolon, while i is greater than 0, then go ahead and print out with printf,
meow, backslash n, and then be sure you decrement i.
And notice that lines 8 and 9 are not only indented, they are inside of that
while loop, so to speak, which means they will both happen again.
And again and again, because what's happening in code here is those curly
are kind of like the yellow pieces that are hugging the other puzzle pieces in
Scratch. It will keep doing this, this, this.
But every time through that loop or cycle, this Boolean expression will be
checked again and again and again until the answer is false, at which point the
computer is going to jump to the last line. And if there's nothing left,
it for the program.
No more to be done.
So same exact idea in Scratch, even though it's a little more mechanical.
So that's how we might implement this.
And you can think of it sort of these variables.
This is perhaps a little gratuitous, but let's do this. So if you have a
variable inside of a computer's memory, and that's a detail we'll get to in more
detail before long, you can really think of it just as like a container that
stores value.
So for instance, this.
Clear plastic bowl can be thought of as a variable. It just stores values.
And right now, there's obviously three stress balls in it, so it represents the
number three.
So what's really happening in code like this is we've initialized i to three,
which is this ball. We're then checking the question on line six, is i greater
than zero?
Obviously. So we proceed inside of the curly braces, and we print out meow.
We then decrement i.
So for the sake of unnecessary drama, like that's decrementing the variable.
what's being stored in this container now is 1 less.
We do it again. Check the count. Nope, 2 is greater than 0, so we keep going.
Meow. Decrement i.
Check the variable.
1 is greater than 0, so we print meow.
Decrement i.
We check the condition again.
i is not greater than 0, because 0 is not greater than 0.
And so the rest of the code stops executing.
I'm not sure if that was any more effective than fingers on my hand. But
the ball. We had the ball. So same exact idea.
Variables are just storing some value. And incrementing and decrementing would
just be adding or subtracting stress balls in this case.
But there's other ways we could do this.
In fact, let me zoom in on my code here.
And it's not really conventional in programming to count down.
Nothing wrong with it. It's just not really a thing we would typically count
So we could alternatively do this.
Set i equal to 1 initially. So we count 1, 2, 3, like a normal person.
And we can change our condition.
If I'm going to count from 1 to 3, what should my comparison be in my Boolean
expression here?
i is less than 3?
Less than or equal to 3, I think. So if i is initialized to 1, we're going to go
through this one time, two times.
three times, i is going to eventually get incremented to four. But at that
point, four is not less than or equal to three. So it's only going to execute a
total of three times. But there's still a bug in this code. What other line
needs to change?
Yeah, so line 9 needs to become plus plus.
So this code is just as correct. And honestly, you could, reasonable people
disagree. Your TF might say, do it this way and not this way. But this is still
correct. But it's not the most conventional way. As per last week,
scientists and programmers generally actually start counting from 0 by
convention for reasons we'll soon see.
So the better way, the more conventional way, arguably, would be always start
counting from 0.
count up to, but not through the number you care about.
And so this form of the code is probably the most popular way to do it. Start at
0, count up to 3, but not through 3, as with less than or equals than. All three
are correct.
Can't really do counting up as easily with the ball without picking up the
balls, but the exact same logic applies.
And in fact, this version of the code is so commonly done that there's a
different way to implement it all. There's a similar way to implement it
together. In fact, this code here, same exact thing, repeating three times,
because it's so commonly done that you want to initialize something to 0 and
keep doing something until the value 3, you can actually use a different
preposition, 4, which is another keyword in C.
And it looks a little more cryptic, but it just tightens things up.
This is what's called a for loop.
Previous is what's called a while loop.
And honestly, even though it probably to the newbie still looks just as cryptic,
it's just a little tighter, because you're expressing all of these ideas on
line. You specify the variable you want to create and initialize.
You specify the Boolean expression you want to check again and again.
You specify what increment or decrements you want to happen. And confusingly,
you do use semicolons here, not commas. You do not put a semicolon here.
You, of course, don't put them after these things. You generally only put
after function thus far.
So we do have one semicolon here.
But in short, this you'll get more comfortable with. This is how I, for
instance, almost always write a loop. But it's doing the exact same thing
mechanically as this. Same thing as counting. Same thing as counting the
balls. There's just different ways to express the exact same idea.
But there are ways to screw up. So in fact, let me go ahead and do this.
Suppose that the cat, we'd like the cat to live as long as possible.
And we don't want it to stop meowing after just three or a finite number of
times. How can you do something forever, again and again and again?
Well, let me go back into VS Code here.
Let me delete all of the code from earlier. And let me go ahead and say
Something is true. I'll come back to that. Let's just go ahead and print out
meow backslash n, ideally forever.
But what do I want to put in here? Well, if I want to do something forever, I
could do something kind of stupid, like while 1 is less than 2, which is always
going to be the case, or while 50 is less than 51, which is always going to
I could just ask an arbitrary question, but like arbitrary, not good in general.
Like you should have meaning behind your code. So if you want the expression to
be true all of the time, just say while true, because true is not changing
anytime soon. If it's literally true, it's always going to be true. The only
caveat is to use this trick for now.
you will need to include the CS50 library, which, for today's purposes,
that possible.
But there's a problem, of course. If the cat's going to live forever, if I do
make cat dot slash cat enter.
Like, you can very quickly lose control over your terminal window.
And you can see the meows are flying across the screen, at least based on the
bottom from what we're seeing. Like, this cat will never stop meowing. And
is either a feature or a bug, so to speak, depending on how long the cat
should live virtually.
But how do you terminate a program that is out of control like this infinitely.
So one of the takeaways for today is Control -C is your friend for cancel or
interrupt the program.
If you ever sort of lose control over a program because you've got intentionally
or unintentionally an infinite loop, you can go into your terminal window, hit
Control -C, sometimes multiple times if it's ignoring you, and that will break
out of the program and just essentially force quit it, like in Mac or PCs.
But let's make one improvement here still.
The last thing we did with our cat in Scratch, before now we'll take a break
a moment, was we defined our own functions. And recall that we did that
abstract away the idea of meowing, because Scratch didn't come with a meow
puzzle piece.
C definitely does not come with a meow function.
We have to implement it ourselves.
So quickly toward the end of week 0, we did this.
Define a function called meow that just plays the meow sound.
And now we have a meow puzzle piece we can use and reuse.
In C, we're about to do this.
And this is going to look a little cryptic, but it's going to lay the
for future weeks when we do this even more. I've got a meow function.
Weird mentions of void.
That just means there's no input and there's no output for this function. It
just does one thing simply.
And that one thing is printf meow.
So how do I use this here code? Here in Scratch is how we used it last week.
When the green flag is clicked, repeat three times the meow.
function. In C, it's going to look like this, int made void and all of that. And
I can use a for loop, a while loop. I'm copying and pasting the for loop version
of the code. Set i equals 0.
Make sure it stays below 3.
Increment it on each iteration or cycle.
And just call meow.
So what's nice here is that we have fairly simply a way in C to create our
functions called meow or anything else that lines up perfectly with what we did
in Scratch. We'll take some time to get comfy with the syntax and remember it,
have to look it up frequently for reference. But let's go ahead and
this. If I go back to VS Code, clear my screen,
let me hide my terminal window temporarily.
Let me go ahead and invent this meow function.
Per the code earlier, I'm going to go ahead and do this.
void meow void.
And again, the two voids mean no input, no output. It just does one thing well.
Printf quote unquote meow backslash n.
And now down here, I can use a for loop. So for, and I know this from memory,
int i equals 0, i less than 3, i plus plus. And then inside of curly braces,
going to go ahead and call the meow function.
Notice When I'm creating the function up here, I explicitly, pedantically say
void, void, no input, no output.
When I use the function on line 13, you just say open parenthesis, close
parenthesis. That's the equivalent of a scratch puzzle piece without a white
oval. You just put nothing there. You don't put the word void.
So that's it. Let me open my terminal window.
Let me run make cat to recompile dot slash cat. And I think I have a working
cat. Now, this is correct.
The only thing I don't love about this version, if I hide my terminal window,
that when I start writing bigger and bigger programs, it'd be nice if my main
function which I told you to take on faith for today, is at the top of the
If only because literally the name main means this is the main part of my
program, it'd be nice if it's the first thing I see.
Which is to say, just to be pedantic, it's very common to put any functions
write at the bottom of your file, maybe alphabetically, maybe organized some
other way.
But you put main first by convention, just like the when the green flag
It was the first thing you always started with last week.
But watch what happens now. If I go into my terminal window.
And Command or Control J is hiding and showing it if you are curious, but
probably you'll just leave it open on your own all the time. Let me do make
again.
And huh, I've screwed up somehow. All I did was move the meow function from top
to bottom, and I'm getting call to undeclared function meow something,
something, something.
Well, what's going on?
Well, C is pretty naive and simplistic.
It's only going to do what you tell it to do, and it's only going to do things
top to bottom, left to right. And unfortunately, on line 8, you are
call a function called meow.
But that does not exist in CS50's header file.
That does not exist in standard IO's header file. It exists at the bottom of
file, at which point it's too late, because I'm trying to use it before it
exists. So I could just undo that and put this meow function at the top of the
file. But you're going to eventually get into a perverse scenario where you
can't put all of your functions above all of your functions. You've got to
a lane at some point. So the solution to this, albeit a little weird and the one
time
in CS50 and programming that it is encouraged and necessary to copy -paste
what you can do at the top of your code above main is just copy -paste the first
line of your own function.
This is the so -called prototype of the function, and it simply describes how to
use the function.
And funny enough, we actually saw this earlier, but I sort of swept it under
rug a moment ago.
Or a bit ago, when we looked at standardio .h and we looked at the
function in the manual pages, I highlighted the header file.
But I also glossed over the so -called prototype, which is, sorry, the first
line of the printf function, just as this is the first line of my meow
This is like a little clue. This is like saying to see, hey, there's going to be
a function called meow that takes no input, has no input, takes no input, has
output. Just know that it exists eventually.
And that will satisfy the compiler.
Because if I go back to my terminal, rerun make cat, it now knows on face,
line four, this function will eventually exist.
And indeed, once it gets to the bottom of my code line, 14 onward, there it in
fact is. So you just copy the one and only first line of your function's code
the top called the prototype.
And now if I do dot slash cat, I get finally, meow, meow, meow, yet again in
this case.
Questions on these here cats?
No? All right.
Last flourish before I keep promising cookies that I promise they exist.
So last flourish, like just as we did in Scratch. So in Scratch, recall that we
parameterized our meow function by letting us tell meow how many times to
so that we didn't need to use our loop inside of our when green flag clicked
block. In other words, if I want to actually have the cat meow a specific
of times, I can actually go ahead and do that proactively with some of my own
code, such as this here in Scratch. When I edited my meow function last week in
Scratch, I specified that I want it now to take an input called n, which
represents some number of times.
And I changed my repeat block not to be 3 perpetually, but to actually have n
generally baked in there instead.
Or actually, instead of just saying place on meow, I had a repeat block
as the placeholder instead of a hard -coded 3.
So how can I now use this in C?
In C, it's almost the same.
It's still void at the beginning of my function name, which means no output
still. It only has side effects.
But what did change vis -a -vis the previous version of meow?
What has changed?
Exactly. Instead of saying void a second time in parentheses, it literally says
int n inside of those parentheses, which means in C, this function called meow
take input. It means the exact same thing as the pink on the left. And
this is why we keep emphasizing the scratch blocks. No new ideas with a lot
these features.
It's just different syntax that you'll get used to over time.
So if I go back into VS Code here and I change this function, let's do that.
Let's change my prototype to be int n, where n represents some number of times.
Let's change the actual function on line 14 to also have int n here.
And let's actually move the for loop from main into the meow function, such
I now have my curly braces here.
I have my print statement inside of those curly braces.
And now, in main, I can get rid of all of that code, just say meow.
any number of times, like three, and just like I did with Scratch, let me hit
Enter, an arbitrary number of times, sort of out of sight, out of mind, now
essence of my program is like one real line of code, meow three times, because
I've abstracted away the idea of meowing and told the cat instead exactly how
many times to meow by way of that function.
OK, I can't keep stringing along cookies so long.
Let's go ahead and take a 10 minute break here. And when we come back, more
cats, more code.
DAVID J. All right.
So we are back and want to add one final flourish to this program because now,
more so than a lot of the examples, now the programs are starting to grow in
length. And indeed, soon there'll be a few dozen lines of code, which is not
uncommon. But let's suppose that we want to stop hard coding three everywhere
and actually prompt the user for some number of meows here. Well, let me do
this. In VS Code, I'm going to go ahead and Get rid of this one line for now,
and let's do something like this.
Let's ask the user for an integer. So int, maybe n for number equals get int.
And we'll say something like just number to give a number of meows. And then
we'll go ahead and actually call meow, passing in not three this time, but
passing in n.
So we are using the return value of get int to store it in a variable called n
on line 8. And then we are passing n as the input or argument to the function
called meow on line 9. And again, the actual implementation of meow on line 22
onward, like who cares, out of sight, out of mind, once it exists. We can sort
of abstract it away mentally, but I'll keep it uptight here anyway.
All right, so let me go ahead and open my terminal window, make cath, dot slash
cath, number.
I can still type in three and it works.
Or I can go ahead and type in five, meow, meow, meow, but it's not actually
meowing five times. Why?
I didn't realize this either. But there's a bug.
DAVID J. Yeah, exactly. So the for loop, when I copy pasted it before, before
break, I actually kind of got lazy and I forgot to change the three to an n so
that it matches the name of the argument that's being passed into meow.
So that was a bug, unintentional on my part, but we have now fixed it here. And
now we are passing this in from main to meow.
So if I make cat dot slash cat.
And type 5 this time, I indeed get 5 meows. But it's worth noting there's
subtleties here in my code in that I've used n a couple of times.
So this is actually deliberate that I've used n twice in this way to induce a
bit of confusion.
But it turns out this n It's actually not the same as this n nor this one. So
what's going on here? Well, it turns out in programming, there's often this idea
of scope.
And long story short, generally speaking, variables only exist in the
which you create them. More down to earth, variables only exist inside of
curly braces in which you define them.
So for instance, suppose I got a little floppy, and suppose I didn't bother
giving meow an input, and I didn't bother giving its prototype an input,
just used n on line 14.
Because why? Well, I already defined n on line 8.
So this is just an alternate universe in which I'm not changing meow to take
input. I'm just using n in two different functions. In main, on line 8 and 9.
Actually, I don't even need that. On line 8 and 9.
And also, again, on line 14.
This code will not work. The compiler will not like this. Why?
Because n does not exist inside of meow. Why? Per the heuristic I offered, n
exists only inside of the curly braces in which it was defined, namely these
curly braces here.
So n is in scope in main, so to speak.
But it is not in scope in meow.
And that's why we kind of have to jump through these hoops and use inputs and
outputs and inputs and outputs and pass things around among functions without
sort of sharing things across functions instead.
Now, I could clarify this and maybe change my argument here from n to times.
If I want to make clear that, oh, this is the number of times I want meow to be
said, I don't have to use n for both. But just realize that if you do, it's
a coincidence.
They are not usable in two different scopes.
All right. Let's do one other thing, though. Let's not only prompt the user
the number here. Let's make sure that it makes sense what number they give us.
So if I do make cat, just to clean things up, dot slash cat, suppose I type
OK, I suppose that's correct. If I say meow zero times and it doesn't meow at
all, that's arguably correct.
But if I type in something like negative 5, it ignores me, which I guess is
better than crashing or freezing or something. But ideally, it might be nice
handle this situation.
And if they give me a negative number, prompt them again for a positive number.
Prompt them again for a positive number. Make the program make sense.
So how could we do that? Well, a couple of ways.
If I go back into my code here, I could do this. I could maybe do something like
a loop, or let's see. So if I get n, so if n is less than 1, then
it makes no sense. So what do I want to do if n is less than Well, I could just
prompt the user again. And I'd say, OK, let's get n again.
And then I can say, if n is less than 1, what do I want to do? I guess we could
ask the user again.
And then if n is less than 1, I could just, again, I can give them three
four tries to get this right. This is obviously stupid. I'm copying and
I'm repeating myself.
There's no end in sight.
I can't do this forever, surely.
So this just feels like the wrong solution.
So there are different ways to solve this problem. And funny enough, a while
loop is not really the best way. A do while loop is not the best way. A for
is not the best way. It turns out there's one other type of loop that we
to introduce that's super useful for getting user input potentially again and
again and again so that the user cooperates.
Specifically, what I'm going to do is this.
I'm going to literally say do the following while something is true.
So it's more of a mouthful. I'm spreading it out over multiple lines.
am I going to put inside of the do block here? I'm going to say int n equals get
int and ask for that number as before, close quote semicolon. And I'm going to
keep asking while, sorry, accidental enter, while n is less than
1 semicolon. So notice the semantics of this. Even though it's a little weird
looking, it does read in English, do the following.
OK, get an int stored in n, and keep doing that while n is less than 1.
But this code, as written, is not quite going to work yet.
Let me try opening my terminal window, make cat enter.
Ugh, damn it. Like, use of undeclared identifier n.
Well, here's where the line number is helpful.
The line number is indicated here, 12, and it's repeated here, 12.
So I clearly screwed up at line 12.
There's not that much going on at line 12.
Why is n undeclared?
in line 12, even though I literally just declared it in line 10.
Exactly, because I declared n inside the scope of the do block, so to speak,
inside the curly braces on lines 9 and 11.
That variable n no longer exists by the time we get to line 12. It'd be great if
it did, but it doesn't, because it violates that heuristic I proposed,
that variables only exist in the scope of the curly braces in which they were
defined. So how do I fix this? Well, it turns out you can declare a variable in
advance. outside of one scope, but then define it, that is, initialize it
elsewhere. So the solution here is actually this.
Inside of the loop, just set n equal to the return value of get int. But per the
heuristic, you've got to declare n, make it exist inside of the outermost scope
of this function.
So it's a little weird, and we're kind of breaking this down into two steps,
this is valid, recommended, correct.
C code.
You declare a variable without giving it any value initially.
And then in line 11, you proceed to give it a value, potentially again and again
and again.
Now, what's useful about a do while loop? So a do while loop, as the name
implies, will do something no matter what. But it will potentially do it
and again and again while some question is true, like n being less than 1 in
this case.
All right, as an aside, why did we not do a while loop? Well, let's think about
that. While n is less than 1, but wait a minute, n doesn't have a value.
OK, so I guess we have to go back to doing get int number colon semicolon.
but while n is less than 1, we're back to the same problem where we have to
repeat ourselves again. So this is why for loops, while loops.
Not the right solution when you want to do something at least once, but
potentially again and again. So the right solution here, again, is this new
final looping construct. I'm just hitting Control -Z a lot, whereby we've
it as follows.
All right, let's try this. Clear the screen.
Make CAS.
Enter. Dot slash CAS.
Let's type in 5.
Still works. Let's type in negative 5. And notice, it doesn't just ignore me.
prompts me again and again and again. Even if I type in 0, I've got to at
give it a positive integer.
Well, this actually seems like kind of a common paradigm. Like, what if we want
to prompt the user for a positive number in other programs, too?
We're nearing the point already, even after just week one, it would be nice to
write our own reusable functions that solve common problems. And eventually,
maybe we can put them in header files as well. But for now, let's go ahead and
do this. I'm going to actually copy all of this code. And I'm going to create
one more function in this file below main called get positive int for
And I'm going to specify that it doesn't need any input, because the only thing
this function is going to do is that exact same thing.
So notice that I've just moved my code from main into a function that's name
describes what it does, get positive int.
I'm declaring n here.
I'm doing this again and again.
And I'm doing that while n is less than 1.
And what am I going to do up here?
I can do something like this. Give me a variable called times for how many times
you want to meow, and just call get positive int.
Let me call in. So now, again, we've abstracted things away. And just like in
Scratch, our final example, which we're called looked a little something like
this, where we just called a function to meow three times. Now we're calling a
function to getText. If I hit Enter an arbitrary dramatic number of times, out
of sight, out of mind, I now have two functions in this world, getPositiveInt
and meow that are collectively implementing this entire program.
But it's not quite correct.
There's one mistake here still.
Notice that getPositiveInt is written slightly differently from the meow
function. And just to be clear, too, let me copy its prototype to the top of the
file, just so we don't make that same mistake I made earlier where I didn't
the prototype at top, so C didn't know what it was.
What is different about these two prototypes at a glance?
Yeah?
GetPositiveInt.
Okay, so GetPositiveInt apparently, and we've not talked much about this,
apparently does have an output.
of type integer.
It's supposed to return an int, hand me back an int. It doesn't have any input.
That's what the void in parentheses meant.
No input, but yes output. And meow, funny enough, is the opposite. Yes
output. Why? Because it has a side effect, the visual thing, where it
something to the screen but doesn't hand me any useful value back like the ask
function or the ask puzzle piece did.
So these are sort of opposite in functionality, which means I actually
return an integer from this function to whatever function wants to use it.
So if I want the assignment operator to work here on line 9, I need to do what
all this time get int, get string, and other CS50 functions have been doing. I
need to, in my own function, return that value, literally with a new keyword
called return.
And this is why I keep sticking out my hand. When you want a function to hand
you back a value, you literally use return and then that value.
That's why we have return value as a term of art, literally this return
So if I open my terminal window now, make cat enter,
huh, I did screw up accidentally.
How? Yeah.
Yeah, so on lines 9 and 10, I made a quick change. I changed my variable to
times, but I stupidly didn't change this. So that's fine. That's why n was
undeclared in that context.
Let me clear my terminal. Make cat once more.
OK, that worked. Dot slash cat. Let's type in 5.
And it's still working.
So again, even though the code is kind of growing and growing and growing, it's
the exact same program we wrote super simply before break. But now we're sort
modularizing it. We're creating reusable functions.
And this is why functions like getStringExists, getIntExists, like CS50
those years ago.
And we realized, why are we copying and pasting these functions in all of these
different CS50 programs?
Let's factor out that functionality into a function of our own. Get int, get
string. Just like here, I'm proposing to factor out this functionality.
Get a positive integer that gives you even more precise functionality.
So theoretically, you could use and reuse it in other programs, too. By not
just putting it here, we could go put it in a file of your own name.
and include it in future programs as well. That's all a library is. Someone
realized, gee, other people, including myself, might find this function useful
again and again.
Let's package it up in our own custom function, just like our custom meow
piece last week, so we can indeed use it again and again.
And the takeaways for now is that unlike Scratch, which was a little more user
friendly, in C, you have to specify if you want your functions to have inputs,
and you must specify if you want them to have
outputs as well.
But more on that syntax to come.
So where does that bring us? So after all this discussion of code, at the end
the day, this is what's important in the world of programming.
Not surprisingly, it's what's important when it comes to grading and evaluating
the quality of code.
One, and first and foremost, is correctness. If the code does not do
supposed to do, what was the point of writing the code? So correctness sort of
goes without saying.
Design, again, is much more qualitative.
It's like getting feedback again on an English essay.
Where reasonable people might disagree, you can make your argument better. You
can structure the paper better. You can structure the code better in the case of
programming. And style is purely aesthetic.
Does it look good? Is it pretty printed, so to speak? Can other people,
colleagues, future, and classmates present actually read and understand it?
That's what we mean by style.
Nicely enough, within CS50's programming environment, you will have tools to
evaluate the quality of all three of these axes, so to speak. So in problem
one onward, you'll be introduced to a command line tool that you type its name
at the prompt called check 50 that will check for you the correctness of your
code. Not necessarily exhaustively, like there might be mistakes you've made
that we don't catch, which doesn't make your code correct, but it is a tool for
finding many of the mistakes in your code. In the real world, you would have
colleagues or yourself would write tests for code you wrote or someone else
wrote.
It is a real -world thing to ensure that systems are designed to work.
We saw the Style 50 tool in VS Code already. You click the Style 50 button.
There is now, thanks to the duck, a Design 50 button, too, also in that top
right -hand corner, whereby once your code is correct and working, like
of my programs have been, you can click Design 50, and the duck will not just
quack, but give you qualitative advice, if it can, on how you can make that code
even better, even before you submit. And of course, there's all of us humans in
the room and online that you can ask these same questions of.
as well.
So let's now solve some sort of real world but still simple problems as
to emphasizing small bite size as we have thus far. So the first of these
programs falls into this category. It's having side effects. So let's implement
one or more functions that takes an argument's input and as its output
these visual side effects. We'll draw inspiration from Super Mario Brothers,
surprisingly, perhaps here. The original one, which was very two -dimensional,
side scroller, left to right, Mario or Luigi move from left to right, and
generally have to jump over things like pyramids or other shapes on the screen.
So how might we go about implementing some of the screens from Super Mario
Brothers, albeit textually? Well, we'll make it a little black and white and
ASCII art, so to speak, here using just our keyboard.
But suppose we want to write a program.
called mario .c that just prints out four question marks. It's not going to
nearly as pretty as what's on the screen here, but the logic is going to be the
exact same as what Nintendo presumably did years ago.
So let me open VS Code, my terminal window. Let's code a program called
.c. In mario .c, I'm going to kind of start with some boilerplate. I know I
to print, so even if I don't know how to do this yet, I'm going to include
standardio .h.
For today's purposes, I'm going to copy, paste, or type out that same line again
and again, int main void.
And inside of my main function, akin to the green flag being clicked, I want to
go ahead and print out four question marks. Well, honestly, the simplest way
can think of doing this is with printf, question mark, question mark, question
mark, question mark, maybe a backslash n to move the cursor, and that's it.
So that is arguably correct.
So let's do make Mario in the terminal, dot slash Mario.
And it's not quite as pretty as the game version of it, but it is, in fact, the
exact same idea.
But here's sort of an opportunity, stepping stone, to do better design.
Like this game changes over time, and not all of the screens have just four
question marks. It might be five, six, or even more.
So what's the right programming construct with which we could generalize
many question marks are printing here?
Like what feature of C do we want?
Like a loop, like a for loop, a while loop, or something like that. And
different ways to do this. But honestly, I proposed earlier that we get into the
habit of reaching for for loops as just very conventional.
So let's do that. For int i equals 0, i less than 4, because that's how many I
want for the moment, i plus plus. And then inside of my curly braces there,
let's go ahead and print out, quote unquote, a single question mark, but no
line.
Let me now go ahead and make Mario.
And can you anticipate a arguably aesthetic bug when I hit Enter?
It's not going to move the cursor to the next line.
But the solution here is a little non -obvious. I don't think this helps me.
I put the backslash n there and I do make Mario again and dot slash Mario,
is this output going to look like instead?
Yeah, like a vertical column of question marks, which, while nice enough, is not
the goal at hand. The goal is these horizontal ones.
So someone else, what's the fix here? It's clearly putting the backslash in
inside of line 7 is wrong.
Yeah, so put it after the loop, and not after the printf line specifically.
after and thus outside of the loop so that after that loop is finished
three total times, it's totally fine to just print nothing other than a
backslash n so long as we now recompile the code, make Mario, dot slash Mario,
and voila.
Now we have four in a row. It's a little generalized.
OK, so we've sort of plucked off a fairly easy problem.
Well, let's go back to the world of Mario and try something that is, in
vertical like this. So this is another scene with three bricks here. Instead of
using question marks, we'll use hash symbols to represent bricks. This
is the incarnation of my mistake a moment ago.
So let me undo this by getting rid of that printf.
Let me change the inside one from a question mark to a hash symbol, which
most similar in ASCII to a brick.
And let's go ahead and put in backslash n after that.
If I do go ahead and do make Mario, dot slash Mario, it's not that interesting.
But, and it's actually not that correct, because I wanted three.
So no big deal.
I can, of course, go back to my code and change the four to a three. Or better
yet, I could use get int or my new get positive int function and just
this further so that I can print out any number of them. But for now, dot slash
Mario gives me three.
All right, so we've plucked off the second of two problems.
Let's now let things escalate a bit. So it turns out once you get to like world
two and beyond, there's some underground parts of Mario where you actually have
bigger, more solid bricks like these here.
And just by eyeballing it, this is like a three by three grid of bricks. Like
nine of them total will conjecture. So how can I go about implementing this?
Well, now is where the program gets a little more interesting.
And the poorly designed way to do this would be like,
printf, hash, hash, hash, backslash n, semicolon, and then maybe printf,
printf. That's kind of correct, but not well -designed. So make Mario, dot slash
Mario. It doesn't look like a square, just because these hashes are more
vertical than they are horizontal.
But it is correct, this example. But it's not very generalizable. And this is
literally hard coding. I copy -paste. And I'm just doing a lot of bad
here. So what could I do instead?
Well, it turns out we can combine today's ideas, including loops, to do
again and again.
So what is this grid of bricks?
It's a three by three.
So it's like a row and a row and a row.
And then within each row, there's column, column, column.
So it too is like an old timey typewriter that sort of prints one line,
next line, then the next line, and so forth. So how can we conjure that in
Well, let me go ahead and do this.
I think an approach would work is like this. For int i equals 0, i less than 3,
i plus plus, because I know I want to do something three times.
But what do I want to do three times? This loop kind of represents in my
eye rho, rho, rho.
So in fact, I could be more pedantic. If I want my i to mean something beyond
int, I could say rho equals 0, rho less than 3.
row plus plus, just to help me think about it.
And then what do I want to do on each row?
What do I want to print?
Like column, column, column.
So brick, brick, brick.
So how do I print three bricks or any number of bricks? Well, I could kind of
cheat and just do printf hash, hash, hash, backslash n. But again, I can't
generalize. I can't take an input from the user and print four or five or six
bricks. So that's going to get me into trouble eventually.
So maybe I could use a loop. So I could do like for int i equals 0, i less than
3, i plus plus inside of my loop. And then in here, I could print out one
And that's kind of on the right direction, the right path, because now
using the simple building block or brick.
but reusing it again and again. And it's totally fine to have nested these
columns in this way.
I used i out of habit, but what would a better name be?
Well, maybe column, or maybe just col, call for short, so that my code is sort
of saying what it does for me.
And I don't have to use row or column explicitly. I don't need to print them,
but I am using them as counters, one after the other.
So let me go ahead and run make Mario, dot slash Mario.
And I'm feeling good about this, but .
Damn it. There's nine brick, but they're not really laid out right.
Why? What's the fix? Yeah.
Yeah, I never went to a new line. And let me do what I think you're not going
suggest I do. Let me just go the obvious place. All right, well, let's put one
right after the brick. But of course, if I do make Mario, dot slash Mario, I'm
making the same mistake as before. I'm printing out too many new lines. So in
between, what lines do I actually want to print a new line?
Between, yeah.
Yeah, so 10 and 11. So outside of the inner loop, but inside of the outer
So it happens again and again. So let's just print out as before, single
backslash n, semicolon. Now let's do make Mario, dot slash Mario, enter. Ah,
it's generalized as I see fit. And if I really wanted to dwell on this.
I could go in, and I could prompt the user with get int or with get positive
int, figure out what row and or column should be. We can make any size brick
that we want. But now we have sort of a nice starting point.
But there's another way to think about this. Because I dare say, especially for
your first CS50 problem set, if you're trying to print bricks and the world of
Mario in this way, it's probably not going to be obvious to come up with
like this and just magically get it working after like 45 seconds in total.
It'll be a struggle at first.
there are some patterns to follow. So one, it's pretty conventional.
Nonetheless... to use just i and then j and then k and then l. And if you've got
nested, nested, nested, nested for loops, at some point nesting, you're
writing bad code. It's not well -designed. But one or two or maybe three
nestings could be an OK thing.
But you cannot use and reuse i again and again. Why?
Because if you're counting i here, but then you're changing i here to do your
columns left to right, you're going to get all of your math out of sync. So you
need two separate variables.
i and j are conventional.
row and column would work too.
But if we go back to this idea of rows and columns, well, let me actually
something out here.
And this might help you instead.
Suppose that you set out on this problem.
You know you want to do something like three times, but you don't quite
understand how to print those rows.
Well, take a baby step, a bite out of the problem, and maybe do this.
Create a function with no output.
just a side effect, whose purpose in life is to print a row.
And how many rows?
Well, maybe n for some number of bricks.
How do you print a row of brick?
Well, let me just think about this in isolation.
How do I print a single row of brick? That's easy. For int i equals 0, i is
than n, if I'm generalizing, i plus plus, and then, whoops, i plus plus, and
then. Inside of my curly braces, go ahead and just print out a single hash.
And at the end, as you suggested, print out a single new line. In other words,
abstract away the idea of printing a single row.
And in fact, at this point in the story, especially if you're struggling to get
started, you don't even need to start with main. Take a byte out of the
that makes sense to you that's smaller than the whole problem.
printing a single row.
Because then you can come in and iterate.
Then you can go in and say, OK, now let's write my actual main function.
So int main void, as always.
And now what do I want to do? I want to print out a whole bunch of rows.
How do I print out a whole bunch of rows? Oh my god, it's like the same
int i equals 0. i is less than, let's call it 3 for now, but we can generalize
that. i plus plus.
And what do I want to do on each iteration of this loop?
My gosh, just print row.
with three bricks.
And then we're sort of done.
Again, out of sight, out of mind. This function can go away and never be seen
before, because once print row exists, that's what it, in fact, does for me.
Now, this isn't 100 % correct.
I still need my prototype, because if I've made my own function, I need to
see in advance that it shall exist. So I need to copy and paste that one line of
code. If I were really being pedantic, this is bad design.
In general, when you have the same number in multiple places in a program,
programmer would call this a magic number. How is that working? You're just
honor system that you're using the same number again and again.
So a better solution here, even if you're not going to take user input,
to do this.
int n equals 3.
and then use n here, and then use n here, or you could call it anything you
want, but now you've specified three in one.
and only one place.
And we can go one step further. It turns out in C and in other languages, you
can protect yourself against yourself.
If you know that a variable should never change its value, it should always stay
3 in this case, you can use what's called a constant, where you can
say, I don't want just n to be an int. I want it to be a const int, const for
short for constant. And this means even if I try to change n in my code, the
compiler will not let me. So I can protect myself from myself or in the
world, you can use a variable that none of your colleagues can foolishly change
on you without you realizing that it has happened.
So a lot of programming, honestly, is just not trusting yourself the next
morning when you've forgotten what code you wrote, let alone the next month, the
next year when you're writing code in the real world. So constants just give
a feature to defend against ourselves.
There's another feature that's useful too, especially when you wake up the
day and you're like, oh my god, how does this code work? What does it do?
Well, there's comments in code. And some of you might have used this in Scratch.
You could add little yellow sticky notes in Scratch for comments.
In code, you can do something like this.
You can, if you want to put an English reminder to yourself, or if you speak
some other human language, a comment in Spanish or any other human language, you
can write it with a slash slash at the start of the line. And then you can say
something like print n.
And then this tells you in a comment what those subsequent lines of code are
doing. It's sort of a note to self. It has no functionality. For the computer's
sake, it just is a note to yourself.
Or you can say something like this, like, never change n, because you're
clear that it's indeed constant. But that, too, is a little pedantic, since
const says the same. But comments are notes to self to help you remember what
something is doing or why you did it this way.
Questions now on any of these Mario problems that we have solved?
No?
All right. So one final set of examples that puts the limit of what computers
can actually do. That's why we've solved every problem I proposed.
That's because I've kind of been skirting some of the underlying
So it turns out that we have not only functions that give us side effects,
visually on the screen, we again have functions that have return values. So
let's focus on those and where things can go wrong. And let's use a bunch of
other operators as well.
Suffice it to say, computers got their start by being really good calculators.
So computer support, addition, subtraction, multiplication, division,
operators represented by the percent sign here, which says take the remainder
something over something else. And there's even more operators than this.
let's go ahead and implement our own calculator of sorts that actually has
bugs along the way. Let me go back over to VS Code here. I'll close mario .c,
open my terminal, and code up one final file called calculator .c. And in this
calculator file, let's go ahead and do something super simple initially.
Let's go ahead and include cs50 .h.
Let's include standardio .h.
Let's do int main void, as always, all boilerplate thus far.
And now let's do something more interesting.
int x equals get int.
And we'll prompt the user for an x value.
int y, prompt the user for a y value, as we've done previously for comparing
numbers. And let's just do something super simple. Let's give myself another
variable, int z equals x plus y.
And then let's print out the sum.
So printf, quote unquote, and I don't want %s here. If I want to print out a
number, someone said it earlier, we want %s for string, but %i for integer,
backslash n.
and print out the value of z.
So it's a little silly, this calculator.
It just adds two numbers together, but it's going to demonstrate some points.
make calculator, enter.
So far, so good. Dot slash calculator.
Let's just say x is 1, y is 2, z is going to be 3. This code is correct,
though it is. Is there an opportunity for marginally better design?
Could we tighten this up, make it shorter? Fewer lines means lower
of bugs, probably?
Yeah.
Yeah, we don't really need a separate variable z.
I mean, it's fine if it's clearer to you, if it's clearer to your TF, if it's
clearer to your colleagues. But honestly, this is so relatively simple,
we just get rid of z and just say something like x plus y here, which is
reasonable as well.
But you don't want to take this to an extreme.
Heck, if we don't need z, do we really need x and y?
Well, we could do something like this.
Let me actually delete these lines of code.
And claim, we can do this all in one very pretty one -liner.
We could do, say, get int x plus get int y.
And notice now, kind of like the join example last time, I'm calling get int
twice.
Both of them return a value.
which is going to be 1 and 2, respectively, based on what I typed
Then I'm doing 1 plus 2.
That's going into printf as the second argument. This is actually correct and
will work. It's just stupid.
Don't do this. We've crossed some ill -defined line where this is just harder
now to read.
And so even though the variables aren't strictly necessary,
I would argue, and I think most programmers would argue, This is just
readable. Each line is doing a little bit less work. There's less chance for
error. It just makes a little more sense. But reasonable people will
So therefore, this is to say, over time too, like you and your TF might
disagree. You and your colleagues might disagree.
And at that point is when the sort of religious debates kick in as to which
is the right way.
All right, so that's one calculator.
Let's do something else that maybe just doubles a number here.
So let me change this to just get one integer from the user. Let's just call
x. And let's just double it quite simply. So printf %i backslash n x times
2. We'll quite simply double it. The star operator is indeed multiplication
this case. So that's going to go ahead and double my number. So make calculator
again, dot slash calculator, Enter. And let's go ahead and type in 1.
And I get back 2. Let's run it again. Type in 2.
I get back 4.
Type it again. Let's type in 3.
I get back 6, and so forth. All right, so that's not bad in this case here.
But what if we actually want to write a proper program here?
In fact, yeah, let's see. This is sort of a meme that comes and goes.
Let me see if you recognize this.
I'm going to go ahead and say.
Another variable, not x. Let's be more specific, like int dollars equals 1.
And then let me deliberately induce an infinite loop. Sometimes it is useful to
induce an infinite loop so long as you eventually break out of it somehow if
don't want the program to run forever.
I'm going to ask the user a question, asking them for a char c using get char.
And I'm going to ask them, quote unquote, here's percent i, period.
Double it and give it to the next person, question mark.
This is ringing a bell. And then we can pass in to Getchar the dollars value
there. So actually, this looked a little cryptic already. I'm going to put a
dollar sign in front of it as though we're actually dealing with US currency.
And what do we want to do? How about if the user says Y for yes, double it and
give it to the next person, then let's go ahead and do dollars.
And let's double dollars. So I can do dollars equals dollars times two. Or
recall the trick for plus and minus. I can also do.
times equals 2, which just doubles it in one line as well. Just a little
syntactic sugar, as programmers call it, that just tighten up your code, even
though it's the exact same thing.
But what if the user does not type y and they want to keep the money?
Well, we have an else condition.
At that point, you don't want to keep asking, asking, asking, asking them with
get char.
Let's just break out.
of this loop instead.
So break is another keyword that if you're inside of a for loop, a while
do while loop, you can forcibly break out of the loop early if and when you
to. And so this sort of satisfies the goal of making sure that this doesn't
forever, but it is going to run again and again and again while we keep
prompting the user with this question.
So let's see now what happens.
Except at the end, let's go ahead and make sure the user knows how much money
they're walking away with.
Here's dollar sign, percent i, backslash n, dollar. So we will see at the end of
this whatever dollar amount the person ends up with.
Make calculator, enter, dot slash calculator.
And let me increase my terminal window size.
So here we go. Here's $1. Double it and give it to the next person. Yes.
Here's $2. Double it and give it to the next person.
Yes. Yes.
Yes. Yes.
Yes. So the Instagram reels aren't that long. But if you keep doubling it again
and again, this is called exponentiation, which will make you
quite quickly. Because notice, we're already in the thousands of dollars by
saying yes and yes and yes.
It's an interesting sort of societal question as to what dollar amount you
keep the money and no longer double it and pass it on. But for now, we'll just
keep doubling it, because this is just getting bigger and bigger, seemingly
infinitely large in the C program.
But oh my god, like apparently,
The Instagram reels cut off the meme too short because eventually it goes
negative and then zero.
Like, what's actually going on here?
Like, the code is actually correct, but we're bumping up against a different
kind of problem.
Any instinct for what is actually going wrong here? It's not doubling forever?
Yeah.
Yeah, there's not enough bits to store bigger and bigger numbers. Recall with
bits, which happens to be how big most ints are, you can count as high as 4
billion if you start at 0, or roughly as high as 2 billion if you want to handle
negative numbers as well, negative 2 billion to positive 2 billion. So
eventually, once I get to $1 billion, it goes negative, and then it just goes to
0 altogether.
This is because of something called integer overflow, whereby if you only
finite number of bits, And you keep incrementing them, incrementing them,
incrementing them.
Eventually, you can't just carry the 1, because there's no 33rd bit.
So all of the other bits wrap around from 1s to 0s. And it looks like all 32
your bits are 0.
Because the 33rd bit was supposed to be the one, but it's not there. They don't
have enough memory. So this is a fundamental problem with computers
you count high enough, things will just start to break, at least if you're using
C or C++ or certain other languages that don't anticipate this.
And there's a very real implication of this. So here's a photograph of
we'll look at more in time to come, like of memory inside of your computer or
phone or any electronic device.
Suffice it to say, there's only a finite amount of memory. And if you're only
using 32 bits then, or heck, even three bits, you will eventually overflow.
We used three bits last week. So here's an example. In binary, if you're only
using three bits per the white digits here, I've put in gray the fourth just
show you what carry we might want to have.
Here's 0, 1, 2, 3, 4, 5, 6, 7, just like last week. And
just like last week, someone said, how do we get to 8? We need another bit.
But if that bit is grayed out because it doesn't exist, we've just overflowed
this tiny integer and gotten back to 0, just like my money went to $0 instead.
So how do we actually avoid that?
One way to do this is this. Let me hit Control -C to break out of the program,
or I could just type no. Let me shrink my terminal window.
and clear it here, I could actually do this.
It turns out that ints use 32 bits typically, but there's another data type
was on the slide before called long, which is a longer version of an int,
is 64 bits, which is crazy big.
There's not that many dollars in the world, but it's still finite, even
can't pronounce the number that big. But if we change all of our int to long,
and we change our placeholder from percent i to percent li for long int, I
actually count higher and higher. So case in point, let me actually go back
my terminal, make calculator, Enter.
Make it larger again.
Dot slash calculator.
And I'm just going to keep saying yes, but faster this time. The sequence is
exactly the same. But recall that once we got into the billions, it started to
wrap to negative and then zero.
This is a lot of money now. Like longs are indeed longer. And I could do this
probably all day long.
Oh, interesting. No, I shouldn't have said that.
Can't do this all day long because eventually a long two will overflow. I
didn't think it was going to happen that fast.
So a long 2 will overflow because we'll need a 65th bit, but the computer has
not allocated it. So that 2 becomes an issue of overflow.
To read an excerpt, like these are very real world issues. And in fact, here's a
photograph of a Boeing.
787 years ago that actually had issues beyond the most recent issues with
airplanes, whereby after 248 days, the Boeing 787 years ago can lose all
of its electrical power due to the generator control unit simultaneously
into failsafe mode, whatever that means.
But if you dig into this, it turns out that there was a software counter in
these airplanes years ago that would overflow after 248 days of continuous
power.
248 days, why?
Well, Boeing was using a 32 -bit integer, and they were using it to
tenths of seconds.
And it turns out if you do the math, after 248 days, you have used too many
tenths such that you overflow the size of a 32 -bit integer. The plane would
essentially have this integer, this tiny, stupid little variable overflow.
But generally speaking, when your numbers suddenly go negative or zero,
things happen. The plane could literally lose its power mid -flight or on the
ground. And if you can believe it, anyone want to guess what Boeing's
was till they fixed the actual software?
What's that?
Not even.
Reboot the plane.
Like, they were told every few days, certainly every 248 days, turn the power
off, turn it back on, which stupidly is what all of us have been told for years
with our Macs and PCs and phones. Why?
Because sometimes, because of bugs in software, computers get into funky
which is a colloquial way of saying, like, some programmer made a mistake,
some counter overflowed, or some condition wasn't handled, and just
unexpected things happen.
So rebooting just resets all of your variables back to their original values
sort of gives you more time. more runway, in this case, no pun intended.
There are others. In fact, one of the most famous ones from the 1980s was the
original Pac -Man game. Only had support for 255 levels.
Why? They were using 8 bits.
Recall that 8 bits gives you 256.
But if you start counting at 0, you can only go to 255. So the crazy kids who
were so good at Pac -Man that they got to level 256, the makers of Pac -Man did
not anticipate that anyone was going to win that many levels. And just weird
stuff happened on the screen. All of the fruit sort of started overwriting
everything because they didn't have enough memory allocated to the level.
did they have a condition that says, if level equals equals 255, you win.
Like, there was just nothing handling that corner case, so to speak. So these
things abound even these days.
Thankfully, in some languages, There are better solutions where you can use big
integers. And you'll just use 64, maybe 128, maybe 256 bits. But you need to use
a language or a library that allows you to grow and shrink the amount of memory
being used. And many, if not most, languages do not do that for us.
So there's a few final problems to see that we've been taking for granted thus
far. And they also involve...
numbers, and memory.
So let's go back into our calculator.
Let's throw away all of this meme code here.
And instead, let's go ahead and do something simple again.
int x equals get int and prompt the user for a variable x. int y equals get int,
prompt the user for a variable y.
And this time, instead of addition, instead of doubling, let's do division.
So printf, quote unquote, percent i, backslash n, and then plug in.
x divided by y. So you use a single forward slash for division.
Let me go ahead and make calculator down here, dot slash calculator.
And let's go ahead and do 1 divided by 3, which should in fact be, well, it's
not really 0, right? It's like 0 .333.
Let's try this again. How about dot slash calculator? 3 divided by 2 should
.5. Nope. Computer thinks it's 1.
Well, what's happening here? Well, it turns out when you're using integers in
program, you are vulnerable to what's called truncation.
An integer plus an integer gives you an integer. An integer divided by an
integer, funny enough, gives you an integer.
So even if the answer is supposed to be 0 .333 or 1 .5, everything in the world
of integers throws away the decimal point onward, and you only get the
part of the value. So it's not even rounding.
It's truncating everything after the decimal.
So this program is just not correct. But there are solutions, potentially.
For instance, if I go back into my code here and I use a different format code
we haven't used yet. We had s for string, i for int. There's also f for
And a float was Like a real number, something with a decimal point in it by
definition. We just haven't used it yet. I could tell the computer to print this
as a float. So let me do make calculator again.
And now, hmm, it's specifying type double. There's an error here.
The problem is that I can't just tell the computer to format this number as a
float. I need to convert.
the number x divided by y to a float.
And I can do this in a couple of ways. One, I could literally change all of
to floats and just avoid the problem altogether.
Use float, use get float, use %f, and I'm done.
But if I want to use ints for whatever reason, because I want the user to type
in integers, but I want to show them real numbers with decimal points for
correct math, I can do what's called casting a value.
I can, in parentheses, which is a weird new use of parentheses, I can say, hey,
computer, please treat the following integer as a float instead, thereby
avoiding truncation. Do not truncate for me. So if I now run make calculator
again. dot slash calculator, and type in, for instance, 1 for x, 3 for y, now
get an actual floating point value.
I'm formatting it as such, and I'm telling the computer to actually
arithmetically calculate it as such as well.
But here, too, I'm kind of cheating you of a reality.
It turns out, let me clear this screen here, and it turns out that there are
fancy ways in printf to tell it how many digits to show you, how many
significant digits.
And the syntax is very weird. I have to look it up constantly. But instead of
just saying percent f, you literally put some numbers in between there. And you
say 0 .5.
And that will say, it's weird syntax, hey, printf, format this to five digits
instead. So let me go ahead and do make calculator again, dot slash calculator.
And let's do 1 divided by 3. And indeed, I get 5.
significant digits there. But suppose I get a little crazy and I want 50
significant digits.
Well, according to grade school, I should just see more like threes. But
this. Make calculator dot slash calculator.
And it turns out that whoever taught you grade school math was kind of telling
you some white lies. Because if you really do it with a powerful Mac or PC
phone, one third is actually 0 .33333334326744079.
Who's right?
Mr. and Mrs. So -and -so from grade school or like the internet?
What's going on here?
What explains this? It all comes down somehow to weak zeros, zeros, and ones.
Why is this floating point number imprecise, so to speak?
What's the intuition? Yeah.
Yes, similar in spirit.
Just as ints only use 32 bits, floats also use only 32 bits. If you want more,
just as int has long, floats have something called double. So I could kind
avoid some of the problem by switching to double, but that's still going to be
finite. And if you think about this intuitively, if you're using a finite
of bits, be it 32 or 64, you can only represent literally so many patterns and
thus so many floating point values, so many real numbers. But how many real
numbers are there in the world?
Like literally infinitely many is the challenge of real numbers. You can just
keep adding numbers after the digits. So how could a computer, Mac PC or
otherwise, possibly represent every floating point value super precisely if
there's not enough patterns to represent every number in the world? Moreover,
the way that computers use to represent numbers sometimes do not allow them to
represent numbers so precisely. We can get more significant digits maybe, but
not 100 % perfection or precision.
So floating point precision too. is a fundamental problem with computers
And unless, again, you're using a specialized language or library that
understands for scientific computing the implications of overflow or
imprecision, your code will have mistakes, much like Boeing discovered,
like Pac -Man discovered as well.
And in fact, just to end on a gloom and doom note, it turns out there's another
problem like this on the horizon already.
So back in my day, everyone was really worried about the Y2K problem, the year
2000 problem. Why?
when computers were invented, most systems were using just two digits,
independent of bits, two digits to represent years.
Why? Computers came out a few decades ago.
Who would think that a computer is still going to be running decades later?
Turns out they were, especially in government and corporations and the
if you're only using two digits to represent years, And the millennium
around, and it's 1999, about to roll over, about to roll over. What comes
1999?
Well, if you're only using two digits, ideally 2000.
But if you're only using two digits, the year zero comes after the year 1999.
And the whole world, truly, you can look it up nowadays on Wikipedia, was
freaking out because there was so much old software in the world that could
had this mistake. And who knows? Planes falling out of the sky, computers
rebooting, freezing. No one really knew because this was an unhandled situation
in code.
So thankfully, the world actually got its act together. The world did not end
the year 2000, and most systems were updated in time without crazy horror
stories. But we're going to have this happen again, because it turns out Just
few years from now, at this point, computers for years have been using 32
integers to keep track of time, in the sense of what time of day it is. And the
point in time they decided years ago was, hey, everyone, let's just keep
of how many seconds have passed since January 1, 1970.
And we can relatively compute time any time thereafter.
So that's great. That gives us a lot of decades worth. But 32 bits eventually
maxes out at like 4 billion. and positive, or 2 billion if you want
positive. And it turns out if you count the number of seconds between 1970 on
up, On the day, January 19, 2038, the world might again end because all of
clocks are going to overflow.
And we're going to end up in the year zero or negative something.
Now, what's the solution there?
I mean, my god, it's the exact same thing. Like, stop using so few bits. Use
more bits. But bits and memory and computers used to be expensive.
Nowadays, storage is so much more available.
But among the things we'll discuss then is how you can throw both hardware and
software at this problem. But for now, maybe set a Google Calendar reminder for
January. January 19th, 2038, and hopefully we'll see you next week.
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.