>> David: Welcome back to CS50, and welcome now
that you are officially enrolled.
This is the end of week one.
So the enrollment numbers are in
and we thought we would share some statistics,
as we like to do in this course; being computer scientists,
we tend to gather lots of data.
Rather than show it to you though first in chart form,
I thought I would show it to you in CS50 program style.
So I wrote a little program called "chart" that,
based on some data I happened to hardcode into the program,
shows us their numbers for the past several years.
You at this point don't see what I'm seeing
because I haven't hit this button,
but now you'll actually see
that I've brought up a terminal window.
So I have so-called SSH'd into the cloud.CS50.net.
I have connected to the course's central server
from my own laptop and via dot slash chart am I
about to run a little program that depicts as best we can
with what with generally call ASCII art --
it's really all you can do in a terminal window like this --
our numbers from the past few years.
So there we were 2007, 2008, 2009, and bam.
So this is you.
We are honestly so happy to have you all
in the course this semester.
It actually seems, based on a quick glance,
that about 225 people are still in bed today.
But that's okay.
This will be our last Friday lecture ever; back on Mondays
and Wednesdays hereafter.
But this honestly really gratifying
for us, for the staff.
Because we have, as you've hopefully realized,
made a concerted effort over the past several years
to really reach out to students on this campus
who might not otherwise have considered this as a field
of exploration, just a one semester course,
or even ultimately a concentration or minor.
So it is my promise to you and it is the huge staff's promise
to you that we will absolutely get you through this course
and you will have a good time doing so.
Just to give you another several fun facts --
and next week, once we've looked at your Problem Set
"Zero Submissions," which, if you haven't filled it out yet,
you'll see asks a few demographic questions,
a few geek-type questions so we can get a sense of the students.
We have this breakdown in the class right now.
So historically, the course is a lot of sophomores who,
like me perhaps, are realizing that they finally have time
to explore beyond their own interests.
But it's a pretty good breakdown.
So if you've been thinking you're, like,
the only senior here who's taking this course: not at all,
there's about a hundred of you, there's about a hundred juniors,
there's a couple hundred sophomores
and about a couple hundred freshman.
So it's a really nice demographic.
We also have graduate students
from the Graduate School of Design, GSAS.
We have 90 extension school students
who are taking the course via distance education,
so we have a huge group that will be joining us
at the 2010 CS50 fair and the those photos you saw a moment
ago depicted 2009's.
We're also happy to say we're not quite at 50% yet,
but the proportion of women in CS50 is now up to 38%,
which is its highest level in 21 years.
So welcome, ladies, to CS50.
So we left off last time with looking at a bit of coding
and teasing you with the upcoming problem set.
So some support structure that's in view for the coming week.
So rather than assign you yet to sections --
which we will do starting this weekend or Monday,
based on the uptake in enrollment, we're actually going
to rework the schedule we had in mind,
so we will announce via email now this we have your official
Harvard email addresses on file --
we'll announce via email in the next couple days how
to officially section for a specific comfort level and such,
but for this first week, so that we actually have a support
structure in place, we'll have what we call "supersections."
So these are open to students of all comfort levels.
There are three different ones on this Sunday,
this Monday, this Tuesday.
Check the website under "sections"
for the times and locations.
And one of them will be filmed, too,
so that if you can't actually make any of the times not
to worry, that video will go online sometime Tuesday
in plenty of time for Friday's pset deadline.
And we also have starting this Sunday,
lead by one of the course's teaching fellows,
what we call "walkthroughs," so this is kind
of programming lexicon.
The idea of a "code walkthrough" refers to the process of walking
through your code verbally or visually with
or without other people.
What we do in these walkthroughs for CS50 is really walk you
through the week's problem set.
This is targeted at the so-called standard edition,
which we expect most students to do.
The hacker editions -- we don't offer specific walkthroughs
since we assume that that crowd generally is ready
to dive into the PDF alone.
But for the majority of folks, know that this resource exists.
I think it's hugely helpful to show
up having read the PDF minimally so you actually get as much
out of this experience as possible.
But it's really a chance,
especially for those less comfortable, to be set off
on a very specific path.
So you don't pick up a document that has a whole lot of Greek,
or what looks like Greek to you and wonder
"Where do I even begin?"
I mean, we'll get you started.
And that's what these will be for on a weekly basis for each
of the remaining problem sets.
So that is this Sunday at 7:00 p.m. Check the website under
"problem sets" for its location.
All right.
So today is about writing some programs and empowering you
to write your own starting this coming week when Pset One goes
out via the website tonight by 7:00 p.m.
So how to write a program.
It's really a three-step process.
You open what we call the "text editor,"
the specific one we used on Wednesday was called Nano,
which is similar to Notepad or TextEdit --
totally simple, kind of dumbed down but in a useful way
so that you can just focus on writing code
and not learning some new interface.
The only interesting commands recall were pretty much CTRL+X
for Save and Quit and CTRL+O for just Save.
You'll see in sections and in some tutorials online
that we'll point you toward that there's other key strokes
as well that will save you time.
And for those of you who want to pick
up a more sophisticated text editor, we will point you
in the direction soon of tools called Vim, or Vi, Emacs.
And then there are other client side IDEs we'll also empower
you with.
So all that's to come.
But once you've written a program, "hello world,"
in a file called hello.c, you Save and Quit.
You then run a compiler, in our case called "GCC" --
one of the world's most popular --
and then you can run it with some number of switches,
these command line arguments as they're called
that somehow influences the behavior of this program.
So this commands, number two here --
can someone just quickly translate
into the English what it is doing for us?
Yeah?
>> Compiling the program [inaudible],
saving it under the name "hello," in the library --
>> David: Okay, good.
So close. Let me tweak a little bit.
So GCC is compiling the source code we wrote,
which lives in a file called --
which lives in a file -- oh, that's right.
Okay, let me correct myself before I correct you.
There we go.
So this GCC is going to compile the source code that's
in the file called hello.c,
but rather than get a stupid default name like a.out,
I'm using this switch first -o for output and hello,
which says actually store the zeroes and ones not
in a file called a.out but in a more reasonably named filed
called "hello."
And now someone else perhaps,
why did I include this -l switch followed
by "cs50" at the tail end?
>> That lets the compiler know that you want
to use some actual compiled code from that library.
>> David: Okay, good.
So that is a flag that tells the compiler that I want to use
or link into my own program code that someone else wrote
that lives somewhere else on the system whose moniker is CS50.
And we briefly saw or mention a couple of others:
there's -lm if you want to use the math library
which has functions like sin and cosine and round and other
such things that you may want to use over time,
but we'll point those out as needed;
there's -lncurses we saw briefly,
which is a very simple graphic library that did
that funkiness toward the end of Wednesday;
and there's a whole bunch of others.
But the take away for now is that if you don't clue -lcs50,
you get some mention -- some error message --
about "undefined symbol," and that should be your clue that,
"Oh it's undefined in that I haven't told the compiler
that I want to link in these zeros and ones."
And then finally, this number three command does what?
>> Just runs it.
>> David: Just runs it.
"dot slash hello" runs the program what do we often see
if you omit -- little sanity check -- the "dot slash" ?
>> An error.
>> David: An error message of some sort like "file not found"
or "commands not found."
And that's because hello.c is something I just wrote --
it's not something I downloaded or bought
and installed via double-clicking or anything
like that -- because I wrote it,
compiled it in my current directory,
I have to be ever-so emphatic to the computer
that it's actually right here.
And "." signifies my current working directory,
the folder that I am currently in.
All right, so let's actually write something a little more
interesting than "hello world."
So among your printout from Wednesday, if you have it,
you have a file called math1.c. If you don't have this,
the programs are short today, so it should be easy enough
to follow along visually, but a PDF
and the actual source code is available online
for these things.
So based on initial impressions,
what does this program do when you run in it?
Yeah?
>> It adds, like, x to y --
>> David: Okay, good.
It adds x to y and stores it into z. But if someone wants
to be a even a little more snarky,
what does this program do?
>> [ Inaudible ]
>> David: Nothing, right?
It actually doesn't do anything at the end of the day
because I am performing this math.
So it's doing something underneath the hood.
It's doing something useful for me.
It turns out not, but it does evince the fact
that we have some basic syntax like mathematics and equal signs
and whatnot with which we can now start using
for more useful purposes.
But let's just quickly point out what this actually does.
And actually, could one of the TFs grab the laser point?
Oh, here it is from Barry.
So this line here declares a variable,
just storage space called "x" and it's of type "int,"
which means an integer has to go in it.
The equal sign is really called the "assignment operator."
And one of the things neophytes trip over early on is
that we'll soon see there's not only an equal sign operator,
there's equals equals.
And we'll see what that means in a moment, and it's just
because they mean different things.
And generally in this language called "C" as well as a lot
of others, almost all of your lines have to end
with semicolons, but not all; just almost all
and we'll see the difference.
Case in point: there's no semicolon here,
there's no semicolon here, there's no semicolon here.
So really, the rule of thumb if you think back to Scratch is
that any time you write a statement --
something that does something in one line of code --
you generally need the semicolon there.
But you'll get used to the syntax before long.
Then I do the same thing on line two
and I declare something called "y."
I assign it a value of 2.
I then create a third variable called "z,"
add those two digits together, store the sum.
But at the end of the day, this program does in effect nothing
because I'm not printing the answer,
I'm not saving the answer,
I'm not doing anything with the answer.
And so when I run this program,
nothing all that interesting happens.
So let's go ahead and compile this gcc math1.c.
And for time's sake, I'm not going
to bother changing the name all of the time, at least for now.
It compiles okay.
The program is called a.out.
So I run this, Enter, and therein lies the nothing.
So let's actually do something a little more interesting.
Let's look at a version two of this file.
And for reference, incidentally,
in case you ever forget what the point of some exercise was,
I'll almost always comment the code up top
with a quick sentence or two
that reminds you what this program does.
So here's one that slightly more interesting.
And now in a sentence, what does this one actually do?
>> Print the answer.
>> David: Prints the answer, right?
So that's the marginal improvement here
and we've seen this syntax before.
Last time we used printf generally
to print a static string, like a hardcoded string, like "David,"
just for example's sake.
But remember that we did introduce a function --
a little utility you can use -- to ask the user for some text,
get it back, and put it in a variable because what's nice
about printf -- and this is what the "f" implies,
format strings -- I can embed inside my double quotes special
strings like "%d" for digits, "%s" for strings,
and there's a few others that we'll see over time.
And that's really a placeholder for the comma-separated list
of values that I put after those quotes.
So it's a useful way of not quite knowing
in advance what you want to put in a string, but being able
to create strings, phrases, sentences, dynamically.
And that's useful because clearly I don't need to know
in advance what the answer is going to be,
what that string is actually going to be.
So just to reinforce this, I could run gcc math2.c
but I'm getting a little tired of this a.out convention
and recall that there's this utility called "make"
that right now doesn't really improve much,
other than give it a better name.
But we'll soon see when the commands you need
to type become longer and more complicated,
they just become annoying to type and annoying to remember
so make generally automates this process for us.
The only difference is I don't type
"make math2.c" I just type math2.
Make then assumes I'm in a file called make math2.c
and goes and finds it.
Now notice the command -- this is not an error message --
make is first showing me the commands
that it is executing on my behalf.
So really, once we start writing more interesting programs,
you would have to type out long annoying commands like that
to just compile more sophisticated programs.
And here we already see a hint that make is going
to simplify all of that for us.
In fact, as a little helper, notice what it's sort
of automatically including for me: What's this thing here?
>> CS50.
>> David: Yeah, so that's the CS50 library.
So just in case I happen to use the CS50 library,
we've configured the cloud in such a way
that make just always provides you with access to it.
So that's useful.
Always provides you with access to the math library
because that's useful, too,
so you don't always have to remember that.
And then there's some other flags,
and we won't spend too much time on these here.
But just so you've been teased with them,
"-ggdb" is a flag that's going to enable what are going
to be called "debugging symbols."
We'll see this in a couple of weeks.
But for the next week or two when you're writing programs,
at least for the first time, generally if you're trying
to debug them like you might have been trying
to troubleshoot Scratch, you're probably going to reason
through it by looking through the your code --
top to bottom, maybe engage a staff member for help --
but your friend will also be printf.
So don't underestimate the value for the next week or two
of just inserting printf statements
into your code temporarily just to print out what the value
of some variable is, or some expression is,
so that you can just do a sanity check.
And then you can delete it once you're sure your code is
working right.
So printf itself is primitive but useful debugging tool.
This thing here hints at more sophisticated approaches we'll
soon take.
Of this detail here, -std=C99 this programming language called
C has been around for some time and it's evolved over time.
In 1999 they added some nice features to it
that make it a lot more pleasurable to actually code in;
they eliminated some of the headaches.
So we are actually using the C99 version of C,
which really means nothing useful today other
than to realize we are using that version.
So if you're coming from prior background,
your code might work a little differently
on a different system if you don't use those flags.
And now pedagogically, all these things, -W, -W, -W,
these are essentially telling GCC to be really nit-picky.
This is telling GC to yell at why you as often as possible,
even about the smallest things to really push you
to write the best, the most secure,
the most correct code possible.
So if you omit flags like those,
sometimes your code will compile fine,
but then you actually compile it with make
or with these so-called flags and you'll be yelled
at a whole lot more, even though you thought your code was
working and this is actually a good thing.
And we'll demonstrate this over time.
But the point for now is just to run math2, which I just did.
And I get an answer of 3, but it seems
to be garbled with my prompt.
Why is this "3" running right into my Malan user name there?
>> [ Inaudible ]
>> David: Yeah, so I didn't have my "backslash n."
So if I open this file, notice I just did "%d."
There's no backslash n --
that would have forced the cursor on to the next row.
So that's all; just a minor little detail.
All right, so let's take things up slightly
to a more interesting one.
Let's go into the third version of this
and then start doing something with these constructs.
So now I'm actually doing some math, but here's some nuances
that we're going to start to trip over.
And this one will be particularly germane
to a portion of Problem Set 1, at least in Problem Set 1.
So what am I doing here?
Well -- and I'll fix this blue next time --
I'm first telling the compiler I need access
to the standard io library
because printf is declared there.
I'm saying "here comes my main function;
here comes the guts of my program."
And here, too, it's just a little baby program
in that I'm hardcoding the expression 17 divided by 13.
And I'm storing the answer in a variable called
"answer" that's of type float.
Now, a float is floating point value.
So unlike an int, this is the type of number
that can have numbers after a decimal place.
And that makes sense because this is not going
to be a whole number, right?
What's 17 divided by 3 is roughly -- one point something,
so one point dot, dot, dot, right?
So why is this relevant though?
Why is this even interesting?
Well, let me compile this.
This is math3, so make math3, Enter.
Now I'm going to run math3.
My program or this computer seems to be broken.
Seems to think the answer is 1.00.
Why is that?
Here's that source code again.
>> [ Inaudible ]
>> David: Yeah.
So that's some good intuition.
We saw last time that there is this remainder operation.
So hopefully there is indeed a way to fix this, but it looks
as though the division operator, the single slash is division
but -- and here's a curiosity
about many programming languages -- because 17 is an integer
and because 13 is an integer, why do I say that?
There's no decimal point; there's no point zero;
there's no floating point value, it's just a hardcoded integer.
The result is that when you divide an int by an int,
the answer no matter what is going to be an int.
So even if the correct mathematical answer is 1.4
or whatever, when you divide an int by an int,
you only have room in that variable, in the response
for an actual integer.
So what happens?
Everything from the decimal point over gets chopped off.
It doesn't round for you.
It rounds down maybe,
but it doesn't round properly as you would think.
It just throws the decimal point away and that's because, again,
these are ints and the answer intuitively should be a floating
point value, but I need to be more specific.
Now as an aside, turns out you can do more interesting
formatting with printf, and this is useful even
for ASCII art purposes.
This time I'm not just saying
"%f" I'm actually saying % -- what -- %.2f.
Now what does this mean?
Well, you can kind of infer.
If I go back to that code from a moment ago,
and I just rerun math3, notice how many places printed
after the decimal point -- two?
So it turns out with printf you can actually control those kinds
of aesthetics as well.
And when that becomes relevant in a problem set,
we'll point you at the appropriate documentation.
So let's fix this.
That was version three.
Let me go ahead and fix this problem.
Well, if intuitively the problem is the result of dividing an int
by an int, surely a solution is: "Don't do that," right?
Instead divide an int by a floating point value.
And I can fix this just by changing one
of those values to a floating point.
Now as an aside, I'll admit this is a completely useless program,
much like the first couple of ones we did
because why would you write a program just to solve this?
You could use a calculator or any number
of other tools but we'll get there.
But here I'm doing the exact same thing except my number here
in the bottom in the denominator is 13.0.
So now when I compile this fourth version with make math4
and then run math4, I indeed get 1.31.
And there's probably more digits after the decimal place,
but because of my formatting string,
I only see a couple of them.
And that's probably useful if you're actually trying
to format things in a nice way.
Let's look at the fifth and final version of this.
It turns out that in a lot of languages, C included,
you the programmer knowing a bit about how the computer works
and the language works,
can exercise more fine-grained control.
You don't need this hack of just, like,
manually adding a decimal point just to fix that problem.
You can compel the compiler to treat some value
as a different type of value,
at least if it makes intuitive sense
that that should be possible.
So here what I'm doing is 17 divided by 13,
but because of this parenthetical, (float),
because of that parenthetical --
that has nothing to do with math;
this is a programming language thing --
that is a casting operation.
So what that means is the compiler is actually going
to first "cast" so to speak 13 from whatever it is
to a float -- to a floating point value --
and then perform the division for us.
So that more rigorously fixes the problem.
Now why is this useful?
Well, we'll talk before long about cryptography.
And cryptography involves scrambling information,
converting what you a human can read into sort of nonsense
that hopefully a bad guy cannot read.
But we know already from week zero
that computers ultimately represent all information
with numbers, and if they want
to represent letters inside memory,
well what do they do or what do they use?
They want to represent letters and not just numbers.
>> [ Inaudible ]
>> David: So yeah, not binary per se but ASCII, right?
You just need to come up with a convention that maps the numbers
that are very easy for a computer to store.
You have to come up with a convention
that maps numbers to letters.
And the thing we've seen thus far is called "ASCII."
Now ASCII involves characters.
We know from Wednesday if -- briefly --
that there's this thing called a "char" or "char," depending
on how you want to pronounce it, which is just a single character
but where there's also an int.
But if we know that 65 is the int that maps
to the capital letter "A," we've already seen verbally
that you can convert letters to numbers and numbers to letters,
and so here's the syntax with which we'll soon be doing that.
If you want to convert a number like 65 to the letter A,
you just have tell the computer "cast that int to a char."
If you want to do the opposite process, you simply "cast
to an int from a char."
So this is a teaser of functionality to come.
Now as for all these data sizes,
let's close one outstanding question.
Here is a program that's a little useful
in that it's just a little cheat sheet for me.
I've declared up top four variables: a char called "c,"
a double called "d," a float called "f,"
and an int called "i."
And those are four of the data types we've discussed thus far.
And I don't quite remember from reading
or from class how big these things are, well,
it turns out -- and this is sometimes useful,
later on more likely than now -- but C has a size of operator
that takes an argument in parenthesis
and it will tell you how much space is used to store
that particular data type.
So I'm printing out line by line a char will take out some number
of bytes; a double, some number of bytes; a float; and an int.
So it's pretty much Copy and Paste.
And the only thing that's differing is the name
of the type and the name of the variable I'm using.
So let's go ahead and make sizeof.
Let's go ahead and run sizeof.
And we should confirm some
of the stuff we started talking about the other day.
So a char is one byte, which is bits -- how many?
>> Eight bits.
>> David: So eight bits.
So that's pretty easy now.
A float is 4 bytes, as is an int.
And an int is interesting
because with 4 bytes, you get 32 bits.
And so what's the biggest possible number you can
represent, give or take, with 32 bits?
>> 4 billion.
>> David: So 4 billion.
Or if you want to tolerate negative numbers,
you've got to sacrifice something.
So it's like negative 2 billion to positive 2 billion.
So this is kind of relevant.
So 2 billion, 4 billion -- these are big numbers,
but there's a lot of "billions of things" in the world, right?
There's billions of atoms.
There's billions probably of web pages these days.
And yet if a computer can only count up to 2 billion
or maybe 4 billion, I mean, what do you then do?
Well, this is actually a problem.
And this is a little different from what happened ten
or so years ago, but the so-called Y2K problem was
essentially the result
of programmers not really having the foresight to realize,
"Maybe we shouldn't use so few bits or so few digits
to represent a year because eventually this will be
a problem."
Now in fairness, that particular problem kind of happened
because so many companies ended up running so much code
for many more years than the programmers actually thought
they would be running it, but the idea is still the same.
So it turns out there's a solution to this:
If you need more precision, more digits after the decimal point
than a float allows, what do you go for instead?
>> A double.
>> David: A double.
And a double is 64 bits.
And now this is getting pretty big.
This is 2 to the 64, and that's a pretty big number.
But in society today, and we'll talk a bit about security topics
and such throughout the course, for cryptography --
for encrypting things like your credit card information
and bank accounts -- you don't use 32 bits,
you don't use 64 bits,
you generally use 1024 bits, 4,048 bits.
I mean, these are huge, huge,
numbers that humans are now using to protect their data.
But it all kind of boils down to these basics of storage.
[ Phone ringing ]
Sorry, I'm getting a call.
Not anymore.
All right.
So any questions?
So a bit of uninteresting math, a bit of focus on sizes
of types, but any questions on syntax
or concepts thus far before we now put this to the test?
Yeah?
>> Is there a data type for representing 1,024 bits or --
>> David: Good question.
Is there a data type?
Is there a key word like int or char double
with which you can represent a 1024-bit value?
Short answer: no, at least not in C. You can construct
such constructs in other languages and in theory even C.
But out of the box,
you generally just get these so-called "primitives."
And actually, it's worth noting an int -- 4 billion --
we didn't even solve that problem.
So what data type can we use to actually get more bits
of precision than an int?
Anyone know what it's called?
So might have been seen long and that might be correct
on some servers, but very, very often the data type called
"long" is actually 4 bytes.
So in fact, if you want a super long number --
let me go ahead and reopen this program --
you could declare long.
So let me try this, long l,
and then let me do a little Copy Paste here
and say a long is actually the size of l. So let me quit
that program; recompile.
And here's a little trick -- and again, we promised to point
out little tricks of the trade --
if I know I want to execute the last command I typed
that started with an m, bangm will actually figure out what
that command was and redo it for me so I don't have
to figure it out, or you can go back
in time in a terminal window.
So I'm hitting the up arrow right now.
Now I'm hitting the down arrow.
So you can scroll back through your history,
which is also useful for time's sake.
So let me go ahead and rerun sizeof and hit Enter.
Well, this is pretty useless, right?
A long, at least on this server, which is a Linux system,
they're the same size.
So it turns out whoever thought of this was either being funny
or just not creative that day.
If you really want a longer number,
it's called a "long long."
It's called that ll.
Let's do a little Copy Paste down here
so I can print out its size.
And if I recompile --
and nevermind that I'm going pretty fast;
I'm doing the exact same thing as before --
hit Enter, now we have 8 bytes.
So 8 is actually a pretty huge number.
And this is very much relevant.
Toward the end of the semester,
we'll talk about database design.
And one or two of your problem sets will actually use an actual
database called MySQL, which is very popular --
Facebook uses it, all sorts of companies use it.
And when you start to store lots and lots of data,
you really do need this ability to count to pretty high numbers.
And thankfully with 64-bit values can we do so,
but sure enough will we run out of space,
even with those types of types.
So hopefully we will not make the same mistakes twice.
All right, so here is a perhaps familiar
if underwhelming formula.
What does this thing represent?
>> How to get Celsius from Fahrenheit.
>> David: Yes.
So this is how to get Celsius from Fahrenheit.
So if you know a temperature F in Fahrenheit,
you can output Celsius.
This is, like, sort of classic Computer Science
101-type question.
It's nice, though, only in that it will give us an opportunity
to fill in the blank.
So here's a blank.
If you have a piece of scrap paper with you,
suppose that you've started your program as follows.
Notice I've made one change.
I was being a little lazy on Wednesday in the interest
of simplifying the code as much as possible.
But it turns out that as we'll see
that functions absolutely take arguments, right?
Printf takes arguments inside a parenthesis.
Main, though, at least now does not take any arguments.
So on Wednesday I just put open parenthesis, closed parenthesis.
But it's the really correct way to specify
that this function takes no arguments is
to actually write this key word "void."
So I'll now start to get into that habit,
even though it's a bit of distracting detail,
it's just consistent with the expectations
that the compiler really has.
So let me challenge you with this:
inside of these curly braces where I have put a comment
with slash slash -- a "comment" means nothing here gets
compiled, it's just for the human to read.
Programmers often write TODO with no space,
all caps like this which means "I have to do something here."
Go ahead and implement with the person next to you a program
that takes as input from the user an integer called F
and prints out the answer of the Celsius equivalent.
So input is an int called F, print out to the screen
or your piece of paper the value
of C. Odds are you only need two, maybe three lines of code
for this, but the goal ultimately will be try it
on your own.
Compare after 30 or 60 seconds with the person next to you
and see if before I reveal the answer we can't get everyone
on to the exact same page.
[ Music ]
>> David: We'll let it loop once more.
[ Music ]
>> David: Called what?
>> [ Inaudible ]
>> David: All right.
So if you haven't already, just glance at the person next
to you, or say hello if you don't know them.
And let's just see how many pieces
of the puzzle you got right.
So there were a couple of hints embedded in here.
A few of you were probably wondering, "Well,
how do I actually get the int from the user?"
Well, remember from Wednesday we introduced CS50's library.
And we've only just begun using it, but it has just a bunch
of very useful functions like GetInt, GetString, GetDouble,
GetFloat, GetLongLong.
And so as those names imply, you can just cull these functions
with no arguments and you'll get back
that data type based on its name.
So I could -- and the hint here is that looks
like you probably do want to use CS50's library
because I've included the so-called header file for it.
Stdio.h, meanwhile, I included in advance why?
>> [ Inaudible ]
>> David: So you need it for printf, right,
if you actually want to print out the value
and not just throw it away.
So this part is the cookie cutter stuff.
Let me go ahead and just to be a little anal add void there.
But we'll explain in the week to come exactly why
and when you do things like that.
And what do you think?
Toward the bottom here, printf?
So you might have chosen a different sentence
or whatnot, but that's fine.
So temperature in Fahrenheit maybe with a space,
just to get the aesthetics to look a little interesting.
Then you declare a float called f and then assign it --
let me scroll up for the folks in front --
that give return value of GetFloat.
Yea or nay?
Most folks at least have something along those lines.
That's okay.
All right.
So not a problem.
So what is this actually doing?
Well, again, recall that GetFloat is a function.
It's defined in CS50's library; its sole purpose in life is
to ask the user for a floating point value and return it.
And it's up to me to put that return value in a variable.
Think of it as a black box.
I say, "Get me a float."
It hands me a float.
I need to now put this float somewhere, and I'll put it
in a variable called f that you can call it whatever you'd like.
And now I have to do the mathematics.
So here I'm declaring a variable called c,
and I'm pretty much translating the formula
from the slide using the characters on my keyboard
to a floating point value.
But there's one potential gotcha here --
and this is where you have to be kind
of piecing together the little clues along the way --
what have I done that's interesting here that had I not,
I would have had a mathematical error?
>> [ Inaudible ]
>> David: Let's go over here.
I think everyone over here seems to know and -- yeah?
>> You changed to 99.0.
>> David: Yeah, so I very deliberately changed this 9
to a 9.0 so that my math would actually be floating point math
involving real numbers and not just integers.
If I left it as just 9, odds are I would very often get
what answer?
>> Zero.
>> David: Right, I would get zero.
Just take a look: if this is 9, 5 divided by 9 is always going
to be 0 point something, and if you thus have two integers
and you're rounding down, which is what happens
when you do integral math we're using this operator,
I'm going to get zero times whatever.
So my answer is always going to be zero
and therefore almost always going to be wrong.
Yeah?
>> But isn't f already a floating point?
So why isn't this [inaudible]?
>> David: Excellent question.
So isn't f already a float?
That's true, but especially because of my parenthesization
over here, because I'm saying, "Do f minus 32,
but then multiply it by the division on the left."
Just as in grade school when you're doing division
and multiplication, you do it from left to right in terms
of order of operations.
The 5 is going to get divided by 9 first.
The answer is always going to be zero.
So yes, f is a float, but that solution is too late;
we need to fix the problem sooner.
>> So how do I switch the parenthesis?
Do I have to put that first?
>> David: So, yes, you could.
If we did that, if we moved f minus 32 over to the left,
that would give me a floating point answer
because f is a float.
Then I'd be multiplying a float by 5,
so that's a float times an int.
That's okay.
That's going to give me a float.
And then I divide by an int --
that's okay because so long as you have a float involved
at some point early on, you're okay.
The problem only arises if you have an int divided by an int.
And that operation is being performed before others.
You'll run into errors.
Yeah?
>> It only works with division?
Like, it doesn't matter, like, you have minus 32 even though --
>> David: F minus 32?
No. So that's not as big a deal.
It's really the multiplication and in this case,
division that the problem arises.
Yeah?
>> Instead of putting 9.0, can you just put
"float" in parenthesis?
>> David: So I could.
Absolutely.
So that's a good application of the alternative I proposed.
I could have just done this,
and the only reason I didn't here is just because now I look
at this, and now it's just getting confusing for me --
even for someone who's been programming for a while.
Just too much parenthesis for my taste.
So I went with the other approach.
But absolutely could you do that.
Yeah?
>> Well, you talked last week about a lot of these.
Why are you, like, writing out code?
Because didn't you say you could do things like just %f?
>> David: %f -- good question.
So when we've talked about "printf" whose purpose
in life is to take some input and then print it
out to the screen,
printf supports what are called "format strings."
They're just placeholders.
But this is a different context.
Here I actually need to tell the computer, "Give me some bytes
in ram in which to store a value, and that value's going
to be a floating point value."
>> So for anything that's not printf,
you have to write out code?
>> David: At some point in time, I'm going to have
to have declared the variable
as a float before I can then hand it to printf
as the insertion value for that format strength.
So both of these stories involve floating point values,
but only in this case am I actually allocating memory.
Other questions?
All right, so let's actually run this thing.
Glancing at the bottom, this is pretty arbitrary,
but I chose to format my string as follows:
so at the bottom here I'm printing out %.1f,
which quick sanity check means print just one digit
after the decimal place.
Then I'm going to print a capital F just
to be aesthetically interesting equals another %.1fc.
So if I scroll now to the right, I should see a comma
after the closed quote and then what two values?
>> [ Inaudible ]
>> David: F, c because I want to tell printf, "Use these values
in those placeholders, these values in those format strings."
So let's go ahead and compile this.
So I'm going to go ahead and run make on f2c,
which is the name I gave to this particular program.
Now I'm going to run f2c.
And now temperature in Fahrenheit --
all right, let's go ahead and pick an easy one like 212,
Enter, and indeed equals 100 in Celsius.
Let's do another one that I know, 32, and that equals zero.
And presumably if we do this again and again,
we'd get back some similarly correct answers.
Okay. So any questions?
Yeah?
>> For the printf, do you use the printf for that?
Could you also use GetString [inaudible]?
>> David: Good question and short answer: no.
So can you use GetString to print the answer?
No. So we deliberately, in CS50's library,
named these functions consistent with their behavior.
So when you have a function called GetString,
that means it's going to get a string from the user --
prompt the user for a string --
whereas printf is literally going to print it,
not to paper, but to the screen.
So it's very much the name of functions that denote
or connote their behavior.
All right.
So let's go ahead and introduce a couple other capabilities
so that we can finally start writing programs
that maybe print out charts or interact with the user,
play games, or the like.
Well, most of this stuff is actually pretty similar
to Scratch.
So it turns out in C, you can absolutely represent the idea
of a condition, a branch, a fork in the road.
The syntax actually looks reminiscent to Scratch,
where you have a puzzle piece reminiscent of this shape,
but you have to say "if" followed by a space,
followed by in parenthesis, the Boolean expression that you want
to check -- more on those in a moment.
The curly braces are then the C's way of kind
of making a puzzle piece that looks like this
so you can put stuff inside.
So the open curly brace followed
by the closed curly brace means everything inside
of these curly braces should get executed,
but only if that first condition is actually true.
You can stack these things in C. So if you want to do if
and then rather -- let me tweak this just so simplify --
if you want to stack these things and do this in one case
or that in the other, can you stack them like this?
And notice, unlike Scratch where some
of you might have realized it starts to get a little ugly,
you have an "if else" and then you have another here
and another one and things start to move and move and move
like this, it gets very messy.
With C you can just line everything up on the left here
because it's just text.
So if we have a third, we can just introduce it like this
and so things start to line up a lot more nicely.
As an aside, if you ever just have one line of code
that you want to execute, one puzzle piece
in Scratch terminology,
you actually don't need the curly braces;
you only need the curly braces if you have two or more lines
of code that you want to execute if that condition is true.
But for now, it's probably simpler just always use the
curly braces just to get into the habit.
Yeah?
>> You said you'd make a space between if and the parenthesis;
does that actually matter?
>> David: No.
Okay, so you caught me
in a small white lie for pedagogical sake.
So the question is: Do you have to have this space between the
if and the parenthesis?
So short technical answer is no.
As a matter of style, the chorus would staunchly preach yes,
for the sake of readability.
So this is a topic that will be threaded throughout the course.
Thus far and in Scratch will pretty much focus on the idea
of correctness: Does your code work as we asked it to
and as you intended it to?
But the two others axis, per the syllabus that we'll explore
in great detail in the course
and also these are the axis along
with which we'll evaluate your submissions are design,
in other words how well implemented is this?
Did you just Copy and Paste 50 times
when you could have just used a loop that cycles 50 times?
So that would be a matter of good versus bad design.
And there's this third axis called "style,"
which is really a more subjective aesthetic sense.
So you will see in textbooks, in programs I write,
in programs the teaching fellows and course assistants write,
very different approaches to style, for instance --
and this is a good canonical example -- a lot of people,
especially those who write C, actually put their curly braces
on this first line and just intuitively someone unfamiliar
proposed why this might be better.
Because there's probably no right answer here,
but why might this approach be better?
Yeah?
>> It seems more [inaudible].
>> David: Yeah, it's just practical, right?
This takes up three fewer lines.
And when I'm starting to write lots of lines of code, you know,
it's frankly kind of useful to be able to see more
on the screen at once without having to scroll.
So I would argue as a matter of practice in my own life
and certainly in a teaching capacity, frankly,
I find this much more readable.
And it's also much more similarly structured to Scratch.
But realize that with these decisions,
it's going to be a matter of style.
And so what you'll be pointed
to in Problem Sets One PDF is something we call the CS50
Style Guide.
You'll see highlighted in green good ways of doing things;
you'll see things highlighted in yellow ways you can do things --
just make sure you're doing it
because you know what you're doing and you
like the way you're doing it; and things in red like this,
which I see surprisingly often because none of us teach this
and yet we see submissions like this:
indenting like this really helps no one as you see in red up top.
So you can do some crazy things because at the end of the day,
the computer really doesn't care.
The compiler is going to ignore all of this so-called
"pretty printing" -- all of this sort of indentation,
all of this white space --
that's really for the human's benefits, both yours,
your colleagues, the teaching staff, and the like.
And so you'll learn over time both by seeing and by doing
that there are generally some good ways, some okay ways,
and some bad ways of actually writing code.
But that's a principle we'll practice over time.
Why don't we go ahead and take a five-minute break?
All right.
So let's actually write a program with this stuff.
So among your printouts are a couple
of files one called condition1.c. I'm going
to change over to my terminal window.
I'm going to use Nano to open conditions1.c.
And actually, I'm going to cheat.
I'm going to use my own special program
that will color code things for me in class,
but the idea is the same; it's a text editor.
And now let's take a look at what this program actually does.
So I've removed the comments, the things that start
with slash slash from the slides just
so you have an opportunity engage more intellectually
rather than just reading the answers off the screen.
Your copies realize have comments
that document everything that's going on.
So here's my code here.
I'm first saying printf.
I'd like an integer please, a colon, and a space just
for aesthetic reasons.
Then I'm declaring a variable called n, it's of type int.
And I'm using the so-called "assignment operator,"
a single equals sign to store in n what?
>> The int.
>> David: The int.
So to store in n whatever GetInt returns.
Now what does it mean to cull GetInt?
Well, as we'll eventually show you the source code,
the code we wrote for GetInt itself.
But for now assume that GetInt just makes the cursor blink
or at least stay steady -- it depends on your computer
and operating system and such.
But suppose that -- think for now
that GetInt just makes the cursor blink or wait
for the user to type in an "int" and then hit Enter.
So that's what it means to get an int.
If you instead use GetString, same thing: blinking cursor,
the function is just going to wait for the user
to type a word, a sentence or whatever, and then hit Enter.
And we'll see if you try to mess with our functions
by providing a string when we want an int, or providing an int
when we want a string, you may very well get yelled at
and the user will have to retry.
So we've embedded some error checking, if you will,
into our implementations.
Now at this point in the story,
I've got a variable called n. I've stored it in int.
What am I now doing?
Well, here is one of these conditions, these branches.
We've used them in Scratch.
If n is greater than zero, I decided I would say,
"You picked a positive number, backslash n," so put the cursor
on the next line, else if n was not less than zero, I say,
"You picked a negative number, backslash n."
And notice because I have just one line of code inside of each
of these branches, what have I clearly omitted?
>> [ Inaudible ]
>> David: The curly braces.
So I actually don't need the curly braces
because I only have a single line of code.
But if I did have two lines of code or more,
I would in fact need to put those back.
Why omit them?
It's just a little more compact, as the gentleman there said.
It just frees up space on the screen for more content
and that may very well be a reasonable decision.
All right, so there's a bug.
The astute or the mathematicians will realize
that what will happen here?
>> [ Inaudible ]
>> David: Right.
So zero is supposed to be neither positive nor negative,
and here I am just simplifying
and saying it's actually going to be negative.
All right, so we can fix this, right?
We've seen this branching construct in Scratch,
we've seen it a moment ago on the slide, and see, we just need
to use not an else, not just an if but an else if.
And so here do we see we can check for equality with zero.
And here as promised is that other operator --
looks a little weird,
but because assignment is already using the equal sign
to assign one value on the right to a variable on the left.
Well, the world had to come up with another symbol that looked
as similar as possible just for people's sanity,
so they went with equals equals.
So this is the equality operator,
whereas the single equal sign is the assignment operator.
So now we have three conditions -- three forks in the road --
and this program is in fact correct, at least hopefully.
Let's go ahead and make conditions2, and hit Enter.
All right, that's good.
So now I'm going to go ahead and run conditions2.
And now notice as promised, I'm using a Mac here
so my cursor is not actually blinking,
but the cursor is waiting there for me.
Nothing is happening until I actually type
in let's say, "David."
Okay, obviously that's not an int.
I culled int and as promised, it's going to yell
at me by saying "retry."
And it will just do this ad nauseam
until I actually give it an int or if I realize, "Wow,
I really screwed up this program.
I can't give it what it wants,"
know that when you're writing code and the problems
that will remind of this, if you absolutely have
to kill your program, you don't have to close the window,
reboot crazy stuff like that, generally you can hit CTRL+C
and it will just abort the program right where it is,
in case you ever get trapped in some awkward situation.
But let's actually play this game properly this time.
So I'd like an integer please.
One, two, three, Enter.
You picked a positive number.
Let's now do negative one, two, three.
You picked a negative number.
And let's run in one more time zero.
You picked zero.
So that's good.
So this program in fact seems
to be doing something helpful finally.
So now let's take a look at how else we could approach this.
Well, it turns out that if you want to check two conditions
and you only care that one of them is true
or the other one is true.
You might want to say in the real world,
if you go to a movie theater for this R-rated movie, "Are you 18
and over or are you with a parent?"
So if you would want to do this condition or this one,
you don't want to break those conditions up because you want
to let those people in or that family in either way if either
of those conditions is true so you can or them together.
In Scratch, the block you may have used
for this idea literally says "or" for or;
in C, two vertical bars.
And if you've never used those, they're usually
above your Return key.
You might have to hold the Shift key or something like that,
but they're standard keys.
And it's double bars -- no spaces in between them.
We'll eventually see that that single bar means
something different.
So double bar means if this condition or this one --
and maybe even both -- are true, go down this road
and execute that code.
If you want to make sure both conditions are true
and they both have to be true for any code to be executed,
use ampersand ampersand.
And this conjures up the idea of and.
And in Scratch did you probably see the key word
"and" on one of the blocks.
So let's see how we might use this.
There is file now called nonswitch.c among
your printouts.
Let me scroll down and take a look at what we can now do.
Our program can get a little more interesting,
a little more judgmental based on our input.
So at the very top, I've coded up the same thing as before:
"Give me an integer between one and ten," or rather,
"give me an integer between one and ten" --
a little different this time.
Then I called GetInt, which is going
to handle the difficult users for me.
If they type in bogus characters, it's going to yell
at them and make them retry, and eventually I'm going
to get handed back an int, which I'm storing in n. Well,
if I actually want to judge this number based on its magnitude,
well, I can say now, "If n is greater than or equal to one."
So on your keyboard, you don't have a greater than symbol
with a minus sign right underneath,
even though you might have that in Microsoft Word
or the like, but that's fine.
In C and most programming languages, if you need greater
than or equal to, use greater than and then right next to it
with no space put equal to, and that conjures up the same idea.
So if n is greater than or equal to 1 and n is less than or equal
to 3, let's just judge this thing a small
number arbitrarily.
Else if n is greater than 4 and n is less than 6 --
let's call it medium -- else if n is greater than or equal to 7,
less than or equal to 10 -- let's call it "big" --
and if the user typed in zero or negative 10 or 20 or whatever,
let's just use the all-inclusive else block and just say,
"You picked an invalid number."
So at this point, now the code's getting a little more
interesting, but it's also getting a little bloated.
It's kind of growing in size.
Are there syntactic alternatives to implementing this same idea?
In Scratch you may have realized that,
"I could implement my program this way
with these puzzle pieces, but it kind of feels
like I could use these puzzle pieces instead" --
that's absolutely the case in programming.
Even though you'll see a whole bunch of constructs today
and even throughout the course, you will find
that there's often multiple ways to implement something,
and it will be up to us to guide you toward better design
and making in giving two different options the better
choice as time passes.
So turns out C supports what's called a switch,
a switching construct.
This thing's nice because rather than do "if" and "and and"
or "or or" and all of this,
you can instead enumerate things a little more cleanly,
albeit apparently at the expense of more white space.
So the top of this program's the same.
"Give me an integer between 1 and 10."
I get the int and store it
in n. The switch statement takes inside its parenthesis an int
or a char or some primitive type.
So for now assume it's got to be an int or a char.
And then what I get to do inside the curly braces is literally
line by line enumerate the cases that I want to apply
to the following code.
So this code is identical functionally
to the last implementation we saw, nonswitch.c,
but I'm just ever-more emphatically saying,
"In case 1," that is when n equals 1
or when case 2 applies --
when n equals 2 or when n equals 3 do what?
I go ahead and print out a small number.
But I now have to use "break."
Break is another key word.
You might have used something similar in Scratch, maybe Stop
or something like that to kind
of stop what you were doing inside a loop or some construct.
I have to break because otherwise the idea
of a switch is that it's going to keep falling through.
And once one of these things applies, it's just going
to start executing code until you tell it to break.
Now at the very bottom, should we see a default case.
When you're all out of specific cases and you want
to handle everything else, you literally say "default:"
And here I could end the program with break, but it's kind
of unnecessary because once I'm at the bottom
of the curly braces, that's it.
There's nothing more that might get executed anyway.
Which one is better?
Honestly, this one looks a little ugly.
You have to kind of scroll down to see it.
But when you start writing programs, especially when we get
to web-based stuff where you want
to check the user's input --
is it valid, is it an email address,
and all these different scenarios --
it's actually often useful to be able to just enumerate them
or rattle them off using this switching construct instead.
All right.
Well, we saw loops in Scratch.
Let's see how we can now start using them like I did
for that little chart of enrollment.
So here is a for loop.
In C and in many languages,
PHP and JavaScript are pretty much going to look the same
to us later this semester, you implement the idea of looping
with any of three constructs: one's called a for loop,
as we're about to see; one's called a while loop;
and one's called a do while loop.
Scratch essentially had the same ideas, but they were call repeat
and forever and a few other options.
So same ideas, just different jargons,
slightly different implementations.
So what does this program do?
Well, main first declares a loop that starts here.
And then there's three parts to the parenthesis
after the key word "for."
The semicolon separates each of the parts.
So this thing on the left is part one, part two, part three.
The general structure that we're looking at can be summarized
as this, if this helps paint a nice mental picture.
The first thing is what we're going to call "initializations."
This is code that's got
to be executed before anything else happens.
It's how you can initialize a variable to like zero
for counting's sake or something like that.
"Condition," this thing in the middle between the semicolons,
is going to be checked every iteration of the loop.
And as soon as this condition or these conditions evaluate
to false, the whole loop terminates.
So unlike Scratch where you pretty much had to say
"repeat" ten times or whatever, or forever where it's just
"forever" with for loops,
can you actually specify a finite number of iterations --
and as I learned 15 years ago, finite is important.
So finite number of times can you specify with a condition,
as we'll see in a moment.
And then finally, updates.
It's not a good thing if you're just looping
and checking some condition,
but never actually changing the state of the world.
If you're not updating some variable by incrementing it
or decrementing it -- if you're not changing anything,
presumably the conditions are never going to evaluate to false
or the opposite, so you're just going to have an infinite loop,
which might be your goal, but odds are it's not.
So how might we use this in practice?
Probably the most common approach to using a
for loop is just to iterate from i equals zero up to some value.
And in this case, it's very reasonable
to use a variable called "i" even though
that conveys very little information
if the whole point is to be an index, just from zero to one
to two, to three, to four,
or even downward depending on your goal.
So this declares an integer, a variable of type int called I,
and initializes it to zero.
This checks "Is i less than or equal to one hundred?
If so, proceed to loop."
I proceed to loop.
I print Percent complete.
And this looks a little messy, but notice what's embedded
in there is some familiar stuff.
%d means --
>> [ Inaudible ]
>> David: Yep, so one or more digits.
"%%" means percent.
So just as we had to escape things with backslashes
in an awkward way, same deal with percent in this context.
If you want a literal percent, it's %% and then backslash n.
So this program, if you run it based on intuition
or little cheat sheets in front of you,
what is this program ultimately going to do for me?
>> It's going to count [inaudible] from zero.
>> David: Yeah, it's going to count from zero
up to one hundred percent.
It's going to be my sort
of simple implementation of a progress bar.
So let's go ahead and try this.
So I'm going to run progress1.
And again, it's kind of a weak implementation.
And we won't wait here one hundred seconds for it
to finish, but we're using the loop, we're updating a variable,
and we're formatting it in a nice way.
And so at the end of the day, a hundred lines later,
it should get to one hundred percent.
And because there's nothing else in the code at that point,
the program should just quit naturally in a good way.
Yeah?
>> Is there a way to get that first percent complete to stay
in the same place naturally?
>> David: So absolutely.
Can you get the percent to stay in the same place?
Because notice there's going to be eventually a problem.
You go from one, which is this wide; then it goes to ten
and eventually it's going to go to one hundred.
So if you're really being anal, things are not going to line
up in a perfect column.
It turns out that you can.
You can specify numbers before d just
as you can specify numbers before f.
And if you don't put a point but just put a number,
this specifies the width of space that will be used
by the number you're inserting there.
And for Problem Set One,
we'll defer to some online documentation for the specifics.
But short answer: yes.
And it boils down to modifying the format string
with just a simple number.
So you can do some neat things.
>> Is sleep [inaudible]?
>> David: Very good question.
So sleep -- as the name implies --
simply puts the program to sleep for a second.
In this case because I'm saying sleep for a value of one,
where does that come from?
Well, I actually unintentionally glossed over that detail.
At the top of this program notice I had to whip
out another header file because sleep is not defined
in CS50's library, it's not declared
in the standard io library, it's apparently defined
in the uni standard library --
unistd.h. Well, how in the world did I know that?
Well, as you'll see in Problem Set One --
to be clear, unless you walk
out of here uncomfortable here today --
realize that we'll very much hold your hand
for this first problem set through these various steps.
It turns out on a Linux system there's this command called
"man" for manual page.
And you can look up documentation
for various functions.
So if I type "man sleep," this is going
to give me the user's manual for a program called sleep,
but there's a gotcha and the problem set it makes clear,
notice that it says at top left sleep one.
Turns out this user's manual, just like a typical book,
has multiple sections or chapters
and Chapter One is generally about programs.
So it turns out there's a program called sleep,
just like there's a program called Nano,
a program called GCC -- that is not what I want.
I want the function, which is a little tool,
a line of code I can include in my own programs
and generally those tools live in sections two
or three of the manual.
So if I specify the number three,
now I'm in the right place.
Again, pset one will walk you through this
and you'll get familiar with this stuff,
even though it looks a little arcane at first glance.
But long story short, if I want to use a function called sleep,
the reason I, the programmer, knew to use that library --
that header at the top --
because it told me to in this little synopsis.
And I read the documentation, did what it said,
and that's how I got my program to compile.
And you'll do exactly that with some handholding
in Problem Sets One.
So let's do make this slightly sexier.
So I'm going to wave my hands at what one
of these things here does, fflush(stdout) here,
but I decided this is kind of a weak implementation.
A progress bar is not supposed to print one hundred lines just
to update its status; generally we
like to see a little animation.
So let me go ahead and compile progress2 instead
and this time run this one.
It turns out that you can keep the cursor on the same line
and update the same line of code again and again
by not using backslash n but instead
by using the more retro backslash r,
which doesn't move the cursor down as we said;
it instead moves the back to the beginning,
much like a typewriter would cycle back the beginning.
So here I'm culling printf in a loop again and again,
but I'm literally overwriting the previous thing that I wrote.
And because I'm writing out a string that's the same length --
my strings aren't getting shorter --
it's creating this illusion of some animation.
But really, the computer's just
so fast I'm drawing the same string
with just a slightly different number again and again
after going to sleep one second at a time.
Yeah?
>> So is there a slash letter command
for printf they could just
like type [inaudible] you know what I mean?
>> David: Good question.
Is there a command to printf?
Not that's as easily said as done.
You could absolutely implement something more interesting
and something even more animated like we saw on Wednesday
or even earlier today, but it takes a little more
than just a format string.
All right, so let's take a look at one last thing here,
one last version of progress.
So in addition to for loops like this,
know that there are while loops.
And when do you use one or the other?
At the end of the day, you can implement the exact same program
using a while loop that you can using a for loop,
it's just your code is going to look slightly different.
And odds are if a week hence, two weeks hence just
for fun you decide to reimplement your Scratch project
or some tiny piece of it, it wouldn't be surprising --
or shouldn't be -- if you end of implementing the same game
or animation or whatever using a completely different set
of puzzle pieces.
Same deal we'd see here.
So with the while loop, you have a condition very similar to the
if blocks and the else if blocks that we've seen.
This is a condition that's checked again
and again every time you cycle around.
But notice unlike a for loop, if you want to declare a variable
or increment or decrement to variable,
you've got to do that yourself.
You've got to do it above this chunk of code,
you've got to do it inside this chunk of code.
The burden is put on you.
You don't get the nice little feature of a for loop.
So we can see this
in progress3.c. This is the exact same program that I had
in progress2.c. It's the fancier version that's actually using
backslash r to move things to the start of the line.
Again, for today let me ignore what fflush means.
It solves a slight bug if we don't use it at all,
but more on that in the future when you talk
about files and creating files.
But notice what I have to do here.
Because the for loop hands me placeholders
in between those semicolons for variables and such,
now I don't have those with while loops.
I got to roll this one myself.
So I have up here at the top of my program a variable called i
of type int, and I have to initialize it up here to zero.
Now I say while i is less than or equal to 100,
I write my code, I sleep for a second.
But here, as we saw in week zero with the shoe example putting
on socks, I have to increment this variable explicitly myself.
Now instinctively, prefer the for loop or the while loop?
>> For.
>> David: Yeah, I'd probably vote for for.
It just feels a little cleaner, but it's going to depend.
And you will see over time as you've seen with Scratch
that there's going to be different ways
to implement these various goals.
Now there's this last type of loop.
So with this type of loop,
things get a little bit reversed.
So the do while construct is not as useful as the other two.
I probably whip out a do while loop very rarely, but very often
when programming games or any program that takes user input
and has to check that user input and yell at the user
if they're messing with you
or aren't providing what's expected.
Now what do I mean by that?
The difference with the do while loop, as the syntax kind
of suggests, is that this construct is going
to do something no matter what.
It doesn't check a condition.
It does something, and then what does it do?
>> [ Inaudible ]
>> David: Then it checks the condition.
And if the condition is true,
then it goes back and does it again.
If it's false, it just breaks there.
So conceptually the key difference here,
besides the syntax looking slightly different,
it just means that if you want a chunk of code
to execute no matter what initially,
you can use the do while loop;
if you want to check a condition first,
you can use the while loop.
So let's see this in practice.
I'm going to open up a program called positive1.c. I'm going
to scroll down to the juicy part here.
It, too, is pretty short, but take a look
at what this one does.
Here, too, gets a little ugly and this is why I tend not
to like this construct, at least in C,
but sometimes it's necessary
or it's the simplest way to achieve this goal.
I declare a variable called n. I'm not giving it a value yet,
so I had better be careful.
One of the details we'll see over time,
especially as we discuss security:
failing to initialize your variables to values you know
about is very bad practice in general because if you forget,
if you're writing a program that's not 6 lines but 600,
leaving things in an unknown state is just asking for trouble
because it's these kinds of things that bad guys try
to take advantage of by putting data there
that you didn't expect.
But for now, let's see if it's okay.
Logically looks like I'm safe
because I know what I'm doing here.
So int n just gives me four bytes for an int,
but it doesn't put anything there yet.
So let's put something there.
Do the following: Print.
I demand that you give me a positive integer.
Okay, I was a little angry when I wrote this.
So next I cull the CS50 function called GetInt.
And what do I do with its value?
I put it in n. So here's where I'm pushing back.
I know this is okay because I'm not using n
until I myself put something there.
So it was a little risky but safe in the end
because I didn't do anything else with it.
Now what do I do?
At this point in the story,
I now check while n is less than 1, what do I do?
This again and again.
So it feels a little backward mentally perhaps,
but this is saying, "do this block of code
as long as n is less than 1."
So the take away is that if the user actually gives me two
or three or four or whatever, this is this expression
"is n less than 1" is going to evaluate to false
if it's actually two or three or four or whatever.
So this do while loop immediately breaks
out at the point of that check.
Now if I am difficult with the user
and I compile make positive1, and I then run positive1.
And again I say "David," well, it's going to make me retry.
Then I type negative1, zero, maybe negative zero.
Still didn't work.
One -- thanks for the one.
And so now it actually spits that out for me.
So what else can we do with this version?
Well, let's take a look at this variant, positive2.c.
So it's a little different.
But notice now I'm getting a little fancier.
And you might have started doing these kinds of things in Scratch
as your programs got more sophisticated.
Here I'm declaring another data type altogether.
There's this notion of a Boolean value named after Mr. Bool,
which is just a notion of true or false.
This doesn't actually exist in C itself.
We put it there via the CS50 library.
We'll pull back that layer before long.
But other languages, Java, C++, and the like all come with Bool.
This is a true or false value.
Because I was taught good style, I'm giving that variable a name
that conjures up the idea of its role, which is thankful or not.
I initialize it to false.
Now what do I do?
I print out -- and this is only wrapping
because of the big font --
I print out, "I demand that you give me a positive integer."
I then do this.
If GetInt's return value is greater than zero,
what do, in plain English?
>> [ Inaudible ]
>> David: I change thankful to true.
Now notice couple interesting things --
GetInt returns a value.
Apparently in this program, I don't actually care what it is,
I only care that it is greater than zero, so it suffices.
It's totally legit to cull a function, get back a value,
do nothing with it other than compare it to another value.
So you don't have to use the assignment operator.
You don't have to declare a special variable for it
if you don't care about its actual value.
So I said thankful to true.
Now down here I can use that other piece
of syntax we just saw.
I want to keep doing this while I am not thankful
for the user's number.
So in other words, if thankful is still false at this point,
it means this condition did not work out very well,
and so I'm going to do this block of code again.
Now this version is arguably a little better
in that it's just a little more clear.
It's a little more readable
because I'm using a Boolean value that tells me,
the programmer, this is true or this is false.
Well, let's clean this up slightly.
Turns out with a Boolean expression,
you don't have use the equality operator equals equals,
you can just say what you mean.
And this starts to make our code more readable, more elegant,
just a little more compact.
So same code up here -- thankful is initialized to false.
I do print this.
I check the return value of GetInt is greater than zero.
I then assign thankful true, if so,
but notice this little trick:
I'm going to keep doing this while I am bang thankful --
bang exclamation point means "not," so this is shorthand,
sort of clever elegant notation for
"while I'm not thankful, keep doing this."
And so you can begin to express --
even though the language is a bit arcane --
your ideas in the same way that you might actually speak them.
So allow me to put this up on the screen now,
which you're now qualified to understand.
[ Laughter ]
I'm very sorry -- we're turning you into the people
who do understand these.
Problem Set One will be posted on the course's website tonight
by 7:00 p.m. It will very clearly walk you
through the week's challenges.
We will see you next week.