DAVID J. MALAN: All right, this is CS50, and this is the
start of week two.
Thank you.
Let us begin here with a phone call.
I'm about to dial 617-BUG-CS50.
CS50: This is CS50.
For Shuttle Boy, press 1.
To start over, press 9.
DAVID J. MALAN: So he said, for Shuttle Boy, press 1.
So we're going to press 1.
CS50: What is your origin?
For quad, press 1.
Mather, press 2.
Boylston, press 3.
Lamont, press 4.
Mem Hall press 5.
To start over, press 0.
DAVID J. MALAN: We'll press 1 for quad.
CS50: Next shuttle leaves this very minute at 1:10 PM, and
then at 1:20 PM, 1:30 PM, 1:40 PM.
This is CS50.
DAVID J. MALAN: So this is CS50's voice.
And it's an example of the sorts of final projects, for
instance, you can bite off toward
the end of the semester.
For instance, that shuttleboy.cs50.net exists--
actually a project that I first wrote after taking CS51
back when I was an undergraduate.
And the inspiration here was-- back then, all they had was
the printed shuttle bus schedules, and there was no
notion of looking things up online.
And so I sort of dove in one weekend, poured through the
printed schedule, and ported it to a computer program.
At the time, the computer program happened to be written
in C. And you actually ran it by typing Shuttle Boy at a
blinking prompt like we've been doing thus far.
But over the years, it's evolved into an instant
messaging bot.
It's evolved more recently into this website, into an
SMS-based tool, as well as into this voice-based tool.
And this is to hint at the sorts of things that you can
do for yourself by semester's end.
For instance, there, the SMS version of Shuttle Boy happens
to operate as follows.
If on your cell phone you send a text message to 41411, and
then send the special symbol sboy, for Shuttle Boy,
followed by A and B, where A is an origin and B is a
destination--
for instance, Boylston Space Quad--
what you should get back within a few seconds is a text
message from Shuttle Boy telling you exactly when the
next few shuttles are, from that point A going to that
point B.
And this is a more general example of what's known as
using an API.
So for instance, this here is just shuttleboy.cs50. net, the
actual web-based incarnation of this.
But the data that underlines this and other apps that CS50
has developed are all exposed to everyone here in the form
of APIs, application programming interfaces.
And that's just a fancy way of saying that people like we on
the internet and others have spent some time creating
software that you can use in order to grab data from us and
then build your own applications on top
of that data set.
So for instance, this Shuttle Boy API page here, which
happens to be in the CS50 manual, essentially documents
how you can go about asking CS50 servers for data.
For instance, if you're familiar with CSV files, comma
separated values, these are just sort of quick and dirty
Excel-like files.
So you can ask Shuttle Boy for all of the data on all of the
houses and their GPS coordinates, and you'll get
back, essentially, a spreadsheet like that, that
you can then read into a program of your own and then
generate results, like Shuttle Boy itself
happens to be doing.
For those more familiar, more modern data representations
include JSON, JavaScript Object Notation.
Something will come back to you toward
the end of the semester.
But again, this is just one of several of CS50's own APIs.
And the exciting thing is now, these days, Facebook and
Twitter and Google and pretty much every popular website out
there has some sort of API, which means if you read the
documentation on their website, you sign up for an
account, you can then start writing software on top of
whatever tools or data that company there provides.
And so one of our own teaching fellows a couple years back
wrote a Mac version of this.
So at the link titled Mac here at top left, you can actually
download a Mac OS widget that runs on your own Mac to do the
same kinds of things.
So it's all about building on top of data sets like these.
But more on that toward the end of the semester.
So let's dive in real quick to a bug, just to kind of get
things warmed up today, and think back on some of the
things we looked at last week.
In particular, let me go ahead and pull up, say,
this example here.
Buggy1.c, this is available on the course's website if you'd
like to download it and poke around yourself.
But let's zoom in here at this fairly short program, and just
a super-fast recap of some of the basic building blocks that
we really are going to just start taking for granted.
So the blue stuff, in lines one through nine, are just
softball questions.
So these are just comments.
They have no functional meaning.
But they're comments in the sense that they're notes that
I, the human, made to myself so that in lecture and after
lecture, I can actually remember what this program
does without having to read through it line by line and
recreating history in my mind.
Moreover, if I hand this program to someone else like
you, it's much clearer to you, because of comments like this,
what the program's actually doing, or at least what the
program's supposed to be doing.
Whether or not it's correct is another matter altogether.
Now, in C, with multi-line comments, recall that on line
one here is the magic symbol, /*.
It means here comes the start of a comment.
And nothing else matters until you reach the end terminator,
which is */, The opposite.
So the fact that I have 80-some odd stars here from
left to right is really just an aesthetic detail.
It has no functional meaning.
Now how about line 11?
What does this do in layman's terms?
What's that?
AUDIENCE: Includes the standard.
DAVID J. MALAN: OK, good.
So it includes the stdio.h library.
So what does that mean?
Well, inside that file, stdio.h, are a whole bunch of
function declarations--
that is, code that someone else wrote.
And a perfect example of a function that's declared in
stdio.h is--
which favorite by now?
So printf, one of the most common ones to use, certainly
early on, from that library is there.
If I exclude that line of code, Clang is going to yell
at me something about using an undeclared symbol.
Something undeclared is probably the keyword, because
we haven't informed the compiler what printf looks
like unless we include that line.
And more down to earth, really what that line is saying is,
open up that file, stdio.h, wherever it is on the server's
hard drive, or the appliance's hard drive, and copy-paste it
right there into my file, without my
having to do that manually.
Now, once we get down here to main, before long we'll start
teasing apart what int and what void is.
But for now, let's look at the three lines
within, 15 through 17.
This here I claim as buggy.
Line seven in my comments says, "Should print 10
asterisks but does not." Why does this not print, in fact,
10 such stars?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Exactly.
So notice that we're starting to count from 0.
And this is actually a convention in programming and
computer science more generally, starting to count
from 0 instead of 1.
And this really just derives from the fact that, for
instance, when we had eight people up on the stage, when
no one was raising their hand, they were
all effectively zeros.
And so it's just kind of a computer convention, so
therefore to start counting from 0.
If that's the lowest number you can represent in binary.
So here we've started initializing i to 0.
We've set i equal to 0.
But then I made this mistake here, saying i is less than or
equal to 10.
But if you think that through, if I start at 0 and then I go
up to 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, I'm actually going to
print out 11 stars to the screen, because I've gone up
to and equal to 10.
So the easy fix here then is what?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Just change it to less-than.
If you really want, you could do this.
But in general, that's frowned upon.
And so starting to count from 0 is just something you should
typically get used to.
Now, what about this whole construct in and of itself?
This line 15 demarks a for loop.
So for is not a function.
It's just a statement.
It's a looping construct, like we saw in scratch.
And it has three parts.
Notice that there is the first part to
the left of the semicolon.
There's the middle part in between the two semicolons.
And then there's the right-hand part to the right
of the second semicolon.
Now, the first of these does what?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Back there?
Yeah?
AUDIENCE: Initialization.
DAVID J. MALAN: Initialization.
So what does this mean?
We have declared a variable called i.
It is of type int, because I've specified inti i.
And I'm initializing i to the value of 0.
So what's this really saying?
It's effectively saying to the computer, hey, give me enough
memory, enough RAM to fit a number, and then put the
number 0 in that chunk of RAM.
And as an aside, how big is an int typically, at least inside
of the appliance?
AUDIENCE: 32 bit.
DAVID J. MALAN: 32 bits.
So that means give me 32 bits, otherwise known as 4 bytes,
and put the value 0 in it, which is pretty easy because
it just means set all the bits to 0.
So now, the second part here is the condition.
And the condition, as the name suggests, is what is checked
again and again and again as to whether it's true or false.
So this is just saying, do the following lines of code--
namely line 16, because that's the only one indented
underneath--
so long as i is less than 10.
And after each iteration through this loop, do the
incrementation, which in this case is i++.
Now, it doesn't have to be i++.
It could be i--.
But if I did this, what's the behavior going
to be of this program?
AUDIENCE: It's going to be an infinite loop.
DAVID J. MALAN: It's going to be some kind of infinite loop,
unless we get lucky after negative 2 billion or so.
Maybe things will wrap around, just by nature of the finite
number of bits that we have allocated for an int.
But it's certainly going to iterate far more than 10, and
certainly more than 11 times here.
And now, just as an aside, realize that i++ and i--
are really just syntactic sugar.
It's just shorthand notation for what's a little more
explicitly written as follows--
i = i + 1.
That is identical to i++.
It just kind of looks prettier to say i++.
It's more succinct, more readable.
And so most people do that instead.
But this is identical functionally to
what we just saw.
So in short, the quick fix here is just to say, iterate i
from 0 all the way up to less than 10.
And then we'll indeed get 10 stars.
So let's try this.
Let me open up the terminal at the bottom.
Let me go into the directory that this is in.
And I'm going to compile it manually with Clang for now.
And I'm going to compile this as buggy1.c, Enter.
And now buggy1, why is there no such file or directory
called buggy1?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Yeah.
So it's actually called a.out.
So recall if you just run Clang, where Clang is the
compiler, and you don't specify the name you want to
give to your program, it's going to default to a.out.
So indeed if I do ls--
oops.
And I didn't-- the black-and-white issue some of
you faced has been fixed.
But let me do this.
There we have a.out on the left-hand side there.
So we have to run a.out instead of buggy1.
So let me go ahead and do this.
./a,out, Enter.
And I apparently did not do what?
AUDIENCE: Save.
DAVID J. MALAN: Save my file.
So that is easily solved by hitting Control S, or going to
File, Save, like in most programs.
Let me go down here, clear the screen, run it again.
And there's still a bug.
So what is going--
AUDIENCE: You didn't compile.
DAVID J. MALAN: Ah, good.
I didn't compile it.
Like an idiot, I'm looking at the code to see what's wrong.
So Clang buggy1.c, now a.out.
And phew, saved.
So it looks a little ugly because there's no new line
anywhere in the program.
But again, that's just an aesthetic detail.
And at least if we count those out, we should
now see 10 such stars.
Well, what about this second warm-up example?
So in buggy2, I claim that this version, too, will print
10 stars, one per line.
So this time, I have a new line character, just to make
things a little prettier.
But instead what I get is this.
So let me do Clang buggy2.c, Enter.
Now it's again called a.out.
Enter.
I only see one new line, only the very last new line that
moves my prompt to the next line.
And yet clearly I've been printing *, then a new line,
*, then a new line.
But what's the bug here?
Yeah?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Exactly.
So unlike some languages, like Python, where indentation
actually has functional meaning, in a
language like C--
as we'll see, PHP, JavaScript--
the indentation is really just for humans benefit.
So the fact that I've indented line 16 and 17 looks great,
but it has no functional meaning here.
If I want both lines to execute as part of the for
loop, then I must enclose them in curly braces by doing this.
You can only cut that corner and omit the curly braces if
what's the case?
AUDIENCE: Just one line.
DAVID J. MALAN: Just one line.
So that's just sort of a nice sort of syntax detail so that
you don't waste time writing three lines, two of which are
curly braces, just to write a single line of code.
But if you have two or more lines, we
indeed need to do this.
So now let me save this.
Let me go ahead and re-run Clang.
Then let me rerun a.out, and now I get them one per line.
Now, a.out again is kind of a dumb name for a program.
How can I tell Clang to actually give me a file name
that's more user-friendly, like buggy2 itself?
A little more clearly?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: OK, so I can actually take the very
user-friendly shortcut and just write make buggy2.
I don't specify .c in this case, and hit Enter.
And what make does is it compiles buggy2.c for me by
asking Clang to do it.
Specifically, it calls Clang, it runs Clang using way more
command-line arguments or switches than I actually need.
In time, we'll come back to what all of these various
cryptic hyphenated expressions means.
But for now, that's just saving me the trouble of
having to remember and having to type out all of those
various hyphenated expressions.
And the upside of it ultimately is
that now I have buggy2.
If I want to do this manually, though, I
can instead do this--
Clang -o buggy2, and then buggy2.c.
And that will similarly give me a file called buggy2.
So in short, Clang's the compiler.
Make is just a user-friendly tool that we'll be using more
and more, because it just starts to
simplify things for us.
And we return 0, lastly.
For now, just because, but we'll start teasing that part
today and on Wednesday.
Any questions on any of this?
Yeah?
AUDIENCE: [INAUDIBLE]
ls in quotes there?
DAVID J. MALAN: OK.
When I typed ls in quotes, that was me doing some magic
behind the scenes to fix a bug.
I forgot, like we've been telling many of you on the
discussion boards, to do--
we'll do this now-- sudo yum -y update appliance50.
Whoops, that that's spelled right.
So the appliance is like an operating system.
It's running this operating system called Fedora.
And now because of my slow internet connection, I've
really hosed it.
So running sudo yum update, as we tell you to do in the
problem set, is essentially like running automatic updates
in Mac OS or Windows.
And the reason for running this at the very start of the
problem set, is because when we created the appliance, I
messed up, and I accidentally made all of your programs look
black on a black screen, which is why you're not seeing them
by default.
But the latest version of the appliance fixes this.
And I'll fix that during break once I have internet
connectivity.
So the quotes just hides my mistake, very discreetly
apparently.
Other questions?
Yes?
AUDIENCE: Where does Make come from?
[INAUDIBLE]
DAVID J. MALAN: Good question.
Where does Make come from?
It is a Linux program that has existed for many years, long
before CS50.
And it comes with an operating system like Fedora.
It does not come from the CS50 library.
In fact, the only things that come from the CS50 library
thus far, that we've seen, are getString, getInt, all of
those get functions, and the word string, and to some
extent, the word bool.
But we'll tease that apart when we dive into the CS50
appliance itself.
So yes, one more question here.
AUDIENCE: When you said Make and then buggy how does the
computer know [INAUDIBLE]?
DAVID J. MALAN: Good question.
So when you just run make buggy1 or make buggy2, how
does Make know?
So by default, if you type make buggy1, Make looks for a
file called buggy1.c.
And then it executes the appropriate Clang commands,
thereby overriding the default output file called a.out.
In fact, if we look at what Make, what--
let's quit this.
If we look at what Make was actually doing, make buggy2,
it's already up to date.
So let me remove the rm command, the
program I wrote before.
Typing Y-E-S to confirm that I want to remove it.
If I now do make, notice that in this very long line,
there's this last thing here, -o buggy2.
All Make is doing is passing that argument, so to speak, to
Clang, so that I don't have to type it myself.
All right, so a quick couple of administrative
announcements.
So for sections, which officially began this coming
Sunday, you'll always want to bring, if
you have one, a laptop.
If you don't have a laptop, do reach out to me by
dropping me an email.
And we'll figure out a workflow.
What generally you'll find in section is that they're part
conceptual, part hands-on.
We'll specifically use the section of questions, part of
the week's problem set, to walk through some of the
conceptual material from lecture.
And that's all in the current problem set.
And we'll also dive into some hands-on activities, sometimes
of which will be required to be submitted, sometimes of
which will not.
For instance, this first week, they're meant just as a
warm-up exercise.
And you'll find that those problems are really just that.
They're meant to be fairly small, but not necessarily
trivial programs to write, that aren't necessarily
exciting in and of themselves, but are good opportunities to
practice with syntax, with new functions, in the comfort of a
section where you have a few of your classmates present as
well as your TF.
And what we'll do over time is use a tool called CS50 Spaces,
whereby instead of just using the CS50 appliance, you'll
instead go to a web page in a browser, where you'll be able
to write code in a browser window during section.
And then if you opt in, your teaching fellow can then show
whatever it is you're typing on your screen in your browser
window up at the front of the class, whether anonymously or
publicly, so that he or she can then walk through with
your classmates what you did well, what you didn't do well.
And again, rest assured all of this can be nicely anonymized.
But it'll be a nice opportunity for much more
interactivity than something like lecture allows.
In the meantime, we'll have these things called super
sections, which are optional but are open to every one in
the class, so that you can do this more collectively for
problem set one.
Here's the schedule.
This is also posted on the homepage at cs50.net.
Notice that there'll be a hacker-specific
one tomorrow afternoon.
And we will film one today and one tomorrow and post those
online within 24 hours.
So if you can't make any of these times, not to worry.
And again, the schedule is online now at cs50.net.
In terms of sectioning itself, you should have gotten an
email instructing you to go to the course's homepage to find
out your section.
If life has changed and you need to change your section,
not a problem.
Go back to that same URL, cs50.net/section, singular,
and you'll fill out the similar form so that you can
then give us your preferences.
And we will follow up by week's end as to what we can
accommodate
Last week, recall that we proposed using CS50 Discuss,
the course's discussion tool, in lecture.
So we had 40 questions that were asked and
answered during lecture.
So it seemed to work well, so we'll continue
trying to do this.
If during lecture, you don't just feel comfortable raising
your hand, not a problem.
Go to cs50.net/discuss, post there, and one of our teaching
fellows will either answer it electronically or raise their
hand on your behalf anonymously to ask, depending
on the nature of the question.
And in terms of feedback, generally psets will be
returned within a week.
Because it takes a little while for sections to achieve
equilibrium, the first pset, 0 and 1, will be a little bit
delayed as things settle down.
But stay tuned for that in the weeks to come.
All right, so let me put on my serious
voice for just a moment.
So this is actually an interesting climate to be
having this discussion, what with all of the other things
going on on campus related thereto.
But CS50 has certainly had its history of this particular
topic, in as much as every year, this course, for many
years, Ad-Boards roughly 3% of the class.
This most recent year, 2011, CS50 Ad-Boarded 35 students.
This is not, I think, due to lack of clarity.
Realize that in the course's syllabus, there is a page of
statement explaining where the lines are.
That same statement is repeated on every one of the
problem sets on page one.
So I mention this today really just to make
folks mindful of this.
And we've tried different things.
And what I thought we would do today is just take a moment to
actually look at some of past cases that have come up.
Rather than keep these as dirty little secrets, actually
point out what students have done and how we have detected
it, and really what the overarching motivation is for
even having this conversation.
So with that said, the line essentially is this--
per the syllabus, you're welcome, you are encouraged to
talk with classmates.
That's the whole purpose of having these collaborative
office hours in Annenberg and encouraging people for the
final project to work together.
But the line is drawn when it comes time to actually write
your final solution.
Speaking in English, totally fine, speaking in pseudo code,
totally fine.
Emailing a classmate your pset, letting them look over
the screen as the hands continue typing,
over the line as well.
Do look to the syllabus for the particular lines.
But just to paint a picture of how this is unfortunately a
reality, realize that there are websites out there that
have solutions from this class and many other classes.
The fact that you or some 3% of you know that this exists
means that we know that this exists.
The fact that there are websites like this where you
can pay someone to actually do your problem sets-- this was
an actual case that came up last year.
This is a website called odesk.com.
And Tim was the name of the person here who was posting on
this website, and asked someone to do his pset 7 in
this particular case.
Well, odesk.com is very Google-able, and we too are
very good at Googling.
Here, too, there are sites-- and this one's rather
atrocious, frankly.
[LAUGHTER]
DAVID J. MALAN: The funny thing about this site is if
you read the About page, they talk about their corporate
culture, and how customer service is their number-one
priority, to make sure that your assignments get
turned in on time.
But in all seriousness, again, the fact that these sites
exist, realize we, too, are cognizant of
these kinds of sites.
And to give you a sense of what forms this generally
takes, we generally don't have great scandals where people
are collaborating on any kind of massive scale, but rather
it's these late-night moments of weakness, where you have so
much to do, it's 4:00 AM, you're exhausted, and you
think to yourself, well, let me just take a look at my
roommate's or my friend's code, or the like.
And the manifestations of this unfortunately involve Student
A submitting something like this and Student B submitting
something like this, which certainly, in a computer
science class, is remarkably easy for computer scientists
to detect with software.
This is another common paradigm, where you've sort of
been working alongside of someone, maybe talking in
English, just fine, pseudo code.
But then it comes time to actually submit, and the psets
just get exchanged via email or Dropbox or the like.
But in an attempt to make it less apparent that this is
what has happened, then this is what's submitted.
This, too, does not trip up well-written pieces of
software like we have to actually detect
these kinds of things.
And indeed what we do is run software that compares all of
this year's submissions against all of past year's
submissions, against everything we found on the
internet, against every job website out there.
It's all very automated.
And so we do this really in great fairness to the 97% who
are really working their asses off in this and in other
classes, and putting in all of that effort so that the work
they ultimately submit is their own.
And I can go on for ages.
These are just a handful of last year's cases.
A few students submitted these files identically for pset 2,
pset 3, pset 4, pset 5, pset 6, pset 9.
In this case, this was quiz 0 and in last year, where two
students submitted identically this sentence among many
others, "The request of type--" dot, dot, dot.
So even in a class of 600, did we detect this
on submitted quizzes.
So in short, this-- frankly, I hate having this kind of
conversation, but this is really a deliberate effort
this year to try to drive down that number.
Because even though we say these kinds of things every
year, I think the reality of having dwelled on it for a few
more seconds than usual, and actually just pointing out
that what might seem like, eh, not such a big deal, at least
think back to this particular moment, both in fairness to
yourself and to your classmates here.
So if you ever have any questions as to where the line
is, please just reach out to me personally.
But the answer is always, completely stressed at the
last minute, cache in a late day.
Or if it's a matter of not having any late days,
honestly, email me personally.
We'll figure something out.
Please do not put your time here at Harvard at risk.
Now, I thought we should lighten the mood, so I
included this as the next slide.
[LAUGHTER]
DAVID J. MALAN: This website was great.
I actually got a little distracted.
There's this one.
And then this one was amazing.
OK, so think of that kitten late at night when making
those decisions.
All right, so back to more fun and less serious stuff, like
conditions.
All right, so we talked briefly about these.
This is something that's probably quite familiar from
the world of scratch.
And in the world of scratch, we have this need sometimes to
go make forks in the road.
Either do this or that or this other thing here.
And when we want to do this, we can use, in C now, this if
else construct.
And then here we have Boolean expressions.
For instance, Boolean expressions here, we can or
them together, in the sense that we have this condition or
that condition.
We can and them together, in the sense that we want to
check this condition and that condition.
And here we have a switch statement now, which is not so
similar syntactically to those kinds of conditions, but it
allows us to do the equivalent of if, else if, else if, else
if and the like by simply enumerating them case by case
by case by case.
So we saw those last time.
And then we started touching upon things like loops.
We saw one of these just a moment ago.
But there are these other looping constructs.
For instance, this one here.
So while (condition), do this thing again and again.
So fundamentally, what seems to be different between this
for loop and this while loop here?
This for loop and this while loop.
Yeah?
What's that?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Good.
So whereas in the for loop condition, there's clearly
more syntax.
There's this initialization, there's this update.
In a while loop, there's just this condition.
So it seems that it's a little pared down versus the for
loop, which means if we want to have variables and we want
to have incrementation, we actually have to
do this thing ourselves.
So let me go ahead and open up gedit.
Let me switch over to the appliance.
And let's just do a quick little example that
distinguishes one of these from the other.
And in the back of my mind here, I should say one thing.
I specifically mentioned the name Tim.
Tim was actually someone that a student tried to find to do
their homework for them.
We had no Tim in that particular section.
So realize, lest I disclosed a student, it was not a student.
It was random person on the internet doing things
by proxy last year.
So We find that, too.
So in this case here, let me go ahead and
open up a new file.
File, New.
This gives me a tab here.
Let me go ahead and save it as loop.c.
Let me go and click Save.
And then down here, let's go ahead and start writing
include stdio.h.
Let me zoom in.
Now we'll do int main(void).
Now let me go ahead and do for int i gets 0; i is less than,
oh, 10; i++.
And now I'm going to go ahead and do print the star that I
did earlier.
And then at the end of this program, we're just going to
print a new line, just so that my prompt
doesn't look all messy.
return 0.
Seem syntactically correct?
So far.
So let's see.
So let me zoom out, go into my terminal window.
And let me go ahead and run loop, because I called this
thing loop.c.
So make loop.
Seems to compile OK.
Let me run loop, and now Enter.
And it seems to have printed 10 stars.
So let's just convert this to a while loop and see what
kinds of issues we trip over.
So instead of this, let me go in here and say while i is
less than 10--
let me get rid of the for loop.
OK, so we have a couple of problems already.
So the condition is the same, but I'm obviously missing the
initialization.
I am missing the incrementation.
So what should the compiler likely tell me when I try to
compile this program?
Yeah?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Good.
So it's going to say something like, undeclared, in this
case, variable i.
And indeed, use of undeclared identifier i.
And so this is in contrast with languages like PHP and
Python and Ruby, with which some of you might be familiar,
where you can just kind of start using variables
willy-nilly and not have to worry about declaring them
explicitly always.
In C and in languages like Java and C++, you have to be
super explicit.
And if you want a variable called i, you have to tell me
what kind of variable it is.
So we're going to have to fix this as follows.
I'm going to have to go up here and type int i; therefore
I have declared a variable called i.
Now, I've skipped one step.
I've obviously not initialized it, but let's see if that at
least makes Clang stop complaining.
So let me remake this program.
All right, now it's just complaining
for a different reason.
"Variable 'i' is uninitialized when used here." All right, so
that's pretty explicit.
Initialized just means setting it equal to a value.
And we've not done that, so let me try equals 0.
Now let's try this again and re-run Clang.
Compiled this time.
And I'm about to run it.
But big old infinite loop, because I've done the
initialization, I've done the condition, but I've never done
any kind of incrementation.
So how can I do the incrementation?
Well, in a while loop, it feels like I'm going to have
to do it inside of the loop, because much like the first
week's examples of doing looping constructs, like with
the socks and with the self-counting, we had to do
something at the very end, like go back to the next line.
What if I go ahead and do this i++ here?
Let's not even compile this.
Catch me already.
What's wrong here?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: So it's definitely not int.
It's i.
And the curly braces, like before,
indentation is not enough.
So now I have this construct.
So while i is less than 10, print a star,
then increment i.
And the way a while loop works is that as soon as you hit the
bottom of the loop, which in this case looks like line 10,
it's going to go back to line six, at which point the
condition will be checked again.
And if i is still less than 10, we'll do lines eight and
then nine, then we'll hit 10, and go back to six, again and
again and again and again, so long as i is less than 10.
So let's re-run Make here.
OK, we've compiled OK.
Let me re-run loop.
And now it actually seems to work.
So pluses and minuses here?
Well, so far there's actually not a whole of plo--
so cute.
All right, that was an-- ah, that was accident.
All right, so let's go back to the for loop.
So for loops are nice because they're super explicit.
And even though they're a little clunky to write, it's
very powerful and it allows you to do
multiple things at once.
While loops don't seem to have a huge amount of value just
yet, because it feels like we just have to do more work.
We have to put the initialization up here, the
update down here, and we have to remember to do all that.
So we'll see in time that while loops actually lend
themselves to just different contexts, different data
structures like lists and hash tables, things we'll get to
mid-semester.
But for now, know that there's this third type known as a do
while loop.
And we've seen this briefly.
And this might be super helpful with pset 1.
Any time you want to do something and then check if
the user cooperated, and if they didn't, do it again, a do
while loop lends itself to that kind of logic.
Because as the ordering from top to bottom here suggests,
do literally means do this.
And do this again and again, what might that be?
Maybe it means calling getInt or getString, and then
checking the value of getInt or getString, and then yelling
at the user if they haven't cooperated by asking them
again and again and again.
Where you want to do something once,
then check some condition.
So let's try this.
Let me actually change this now to a do while loop.
And I'm going to go ahead and do the following.
So do the following.
Let's do inti i = GetInt (); but let's first tell the user
what to do.
So a little different this time.
"Give me an int".
So I'll use printf for that.
And now I'm going to go down here, and I'm going to do this
while i is, let's say, greater than--
let's see, i is let's say less than 0, or i is
greater than 10.
In other words, I want a number from 1 to 9, just
arbitrarily.
So I'm using a combined Boolean expression here to
make sure that i is less than 0 or greater than 10, in which
case I will do this loop here again.
So again, do this--
while i is less than 0, or i is greater than 10.
So now let's go ahead and do this once we've done that.
Let's just do a quick sanity check.
printf ("Thanks, i is %d i").
So this simple program asks the user for an int.
Make sure it's within some range 1 to 9 inclusive.
And then thanks the user by reminding them what they just
typed in, just as a little sanity check.
But let's see if this works as intended.
Let me go head down here and re-run make loop.
Hmm.
"Use of undeclared identifier 'i.'" That's strange.
I thought we resolved that.
Same symptom but different code.
Yeah?
AUDIENCE: [INAUDIBLE] inside the two, we have to
[INAUDIBLE].
DAVID J. MALAN: Exactly.
So this actually leads us to a topic known as scope.
It turns out that C, again, it really takes you literally.
And if you do something like this where you declare an int
and then assign it some value, but you do that inside of a
pair of curly braces, what C does is it assumes that you
only want those 32 bits known as i to exist within the
context of those curly braces, within the context of lines
six through nine So i is declared, and it is assigned a
value in line eight, but as soon as you get outside of
line nine below the curly brace, i is no longer in
scope, so to speak.
S-C-O-P-E. It's no longer in the right context.
So now there is no i, so it's as though we hadn't even
declared it at all.
So what's a fix then for something like this, if the
reason is that i is declared within the curly braces, which
is apparently bad?
Here?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Yeah.
So we can initialize it outside.
So let me go ahead and delete the declaration parts whereby
I specify the type, and let me do it up here.
So in line five, it now says "Give me an into." Call it i.
Notice in line nine, I do not want to do this, because I
already have the 32 bits.
I don't want to ask the computer for a
different 32 bits.
I want to use those same 32 bits.
And now because i is declared in line five, it's still legit
to use it in line 11 and line 12.
So let me try to recompile this and see
if Clang stops yelling.
Make loop.
So now it is "implicit declaration of function
'GetInt' is invalid in C99." What is that?
Yeah?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Yeah.
So now that I'm actually using getInt, this is not something
that just comes with C. This comes from CS50.
So we need this here.
And let me go back to the prompt down
here and re-run make.
OK, finally.
Now we've resolved that and the other error.
Let me now run loop and see what happens.
"Give me an int." I'll give it 11.
I'll give it negative 1.
I'll give it foo.
I'll give it 5.
And now it indeed works.
But the prompt changed for a reason here.
Why did it say retry one of these times, but give me an
int the other three times?
Why is that behavior different?
AUDIENCE: Gave it a string.
DAVID J. MALAN: Sorry?
AUDIENCE: You gave it a string.
DAVID J. MALAN: Yeah.
So we gave it a string in this third attempt,
when I typed foo.
Foo is a string.
It's obviously not an int.
And the way that CS50 has implemented getInt is that we
don't check if something's less than 0 or greater than 10
for you, because how do we know in advance what kind of
int you want?
But we can minimally check for you, did the user at least
type an integer?
And if they didn't, we yell at the user by typing "retry on
the screen.
So now we have a program that's looping OK.
Now, which of these is sort of the better construct?
So this is where things start to get a little messy, the
fact that you have to remember to declare a variable up here
if you want to use it inside of some
curly braces and outside.
But even if this looks a little cryptic at first
glance, just again, remember the simple logic.
In order to use anything in C, whether it's a function or
it's a variable, you have to include it if it's a function
in some library, or you need to declare it.
But now you need to be extra mindful of the fact that
you're declaring it in the right scope.
You're not putting it too tightly inside of parentheses.
So let me actually roll back.
If we go back to our for example from earlier, and I go
back to for int, int i gets 0; i is less than 10; i++, and I
do printf stars, like this, and then close paren, and now
printf i is now--
according to the same logic, what will happen when I try to
compile this program?
AUDIENCE: Invalid identifier.
DAVID J. MALAN: So it's another invalid identifier,
undeclared identifier.
Now, the reason's a little different.
There's obviously no curly braces here, but the same
idea, the same story of scope applies.
If you have declared a variable like i inside of a
for loop, even if you have not explicitly written the curly
braces, think of them mentally as still being there, in which
case i is only valid inside of the for loop.
It is not valid once you get to the next line, which in
this case is now 10.
So just a few issues of scope and the like.
All right, any questions?
All right, so this is kind of a trivial little program,
printing just little stars.
But let's see if you remember this song here.
This is an incredibly annoying song the kids would sing on
the school bus and the like.
But what's nice about it is that it has this cyclicity,
whereby it's "99 bottles of beer on the wall,
99 bottles of beer.
Take one down, pass it around, 98 bottles of beer on the
wall." And then the song repeats the 97, then 96, then
95, then 94, all the way down to 0 if you actually got that
far on the bus.
So this is a nice program to sort of implement, because, my
god, if you could just implement this with a few
lines of code, you could spit out the entire lyrics to this
song quite quickly.
But along the way, we can start to now tease apart some
of these basic looping constructs, and now also
introduce functions that we write ourselves, return values
that we pass around.
But first, why don't we go ahead and take our five-minute
break here?
And when we get back, we will sing this song.
All right, so we are back.
And when I say we will now sing this song, I mean
programmatically, not verbally.
So here we have beer1.c, which is one implementation of this
particular song.
And just to be clear, for those unfamiliar with what
this thing looks like, let me go ahead
and make beer1, Enter.
Now let me run beer1, and what we'll see-- how many bottles
of beer will there be?
I'll type in 99, like the song says.
Enter.
And now if we scroll through--
oops-- if we scroll through all of this, we'll see that
this did indeed sing the whole song.
Wait a minute.
My scroll bar's a little messed up.
Let's use the bigger window.
So beer1, 99, there we go.
So here we have the whole song, sung much faster by the
computer than it could have been by us.
So notice, though, the cyclical nature here.
It says 99, then 99, then "take one down, pass it
around," then 98.
And now it repeats again and again.
So this is actually a perfect opportunity for some kind of
looping construct.
Notice that I'm kind of cutting a corner here.
Notice that I'm saying "98 bottles of beer on the wall,
97 bottles of beer on the wall," and that was just so
that when we get to one bottles of beer, I don't have
to worry about the English grammar.
But we can also fix this with a little bit of an if
condition, perhaps.
If this number is singular, go ahead and say "bottle,"
otherwise if it's plural, say "bottles."
But for now, I'm completely cutting that corner.
So let's see what we've got here.
So we've got some comments at the top.
I'm including these two libraries, as
we've commonly been.
And now let me scroll down to the first
actual lines of code.
Line 17 kicks off main.
Line 21 and 20 has how many bottles of beer will there be?
And then I call getInt.
And now I have a bit of a sanity check.
So this is a convention that we'll now start adopting to
more rigorously check the user's input.
Sometimes you just don't want to prompt them again
and again and again.
If the user screws up and doesn't cooperate, fine.
Quit and just don't deal with them.
And so that's what I'm doing here.
If n is less than 1, I'm just going to yell at the user,
"Sorry, that makes no sense." And then I'm going to
arbitrarily return 1.
So again, this is just a convention to get used to.
For now, take it on faith.
But up until now, we've always been returning 0, because
we've said returning 0 denotes what?
AUDIENCE: Success.
DAVID J. MALAN: Success, that's all.
So now that we're finally starting to think about
non-successes--
in other words, corner cases, error conditions--
now I have an infinite supply, or at least four billion
possible things that can go wrong in my programs.
And I can start assigning them individual numbers.
Now, generally it suffices to just return
something other than 0.
So we're going to simply return 1 for now.
But the reason for returning 1 is that as soon as you return
1, guess what happens to the rest of the program?
It stops.
That's it.
So the fact that I'm returning 1 is effectively
short-circuiting this program's execution so that
nothing below line 27 will continue executing.
As soon as main returns, that is it.
All right, so if the user does cooperate and we reach line 30
because they typed in a legitimate number, here is my
implementation of this song.
So I first print out a new line character, just for
aesthetics.
I now have a for loop.
And notice I'm doing things in a bit
of a different direction.
I don't have to do less than, I don't have to do ++.
I can instead say, initialize a variable i, set it equal to
n, the number the user typed in, then do the following, so
long as i is greater than 0, then i--
once you've finished one iteration of this loop.
So we can count down using a for loop as well.
Now, this is pretty much week one stuff now, with printf.
So print "%d bottles of beer on the wall." Print "%d
bottles of beer." "Take one down, pass it around." Print
"%d bottles of beer on the wall." So it's still %d, but
notice that the argument to printf is changing.
After the comma, I have i, because I want to say 99.
After this comma, I have i, because I want to say 99.
After this comma, I have i - 1, because I want to say 98 in
this first iteration, and so forth.
And now down here, I just have some stupid little remark.
And then line 42, I return 0 by convention, signifying that
everything is OK.
So what if I goofed?
What might a common mistake here be?
Well, what if I accidentally said, well, I do want to count
down to 0, I want 0 bottles of beer on the wall?
So I say, i is greater than or equal to 0.
What's going to be the symptom that I now see if I recompile
beer1 and run it?
AUDIENCE: Negative.
DAVID J. MALAN: Yeah, it's gonna go negative.
This is an off-by-one error, an incredibly
common mistake to make.
Let's actually go back to the terminal window and do it
here, so we can see more at a time.
Enter, 99 bottles of beer.
Close, but we went ever so slightly too far.
We sang the song too far down, such that we now hit the
negative number.
So it doesn't quite work.
All right, so we can easily fix that by going back to the
way it once was.
But what are some opportunities now for
improvement?
Well, let me open beer2.c and scroll down here, and take a
look at this version.
What's the first thing that jumps out at you as different
in this version here?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Yeah, so no more i, because it occurred to
me, you know what, I'm asking the user for n, and then I'm
setting i equal to n, and then I'm changing i, but I'm never
touching n again.
So what the heck was the point of you allocating another 32
bits called i just so that I can have a different variable?
So in this case, I sort of recognized that unnecessary
design feature.
And I'm now going to say, while n is greater than 0, go
ahead and print the same song, passing an n to printf as the
second argument, and n - 1 as the second argument down here.
And then on each iteration of this loop, go ahead and just
decrement n itself.
Now, functionally, this program
is going to be identical.
If I type in 99, n starts at 99.
I decrement, decrement, decrement, decrement.
I'm going to get all the way down to "One bottle of beer on
the wall, one bottle of beer.
Take one down, pass it around.
0 bottles of beer on the wall." The end, because I did
get the condition correct.
It's greater than 0.
I didn't make this mistake.
So which is better, version one or version two?
So I heard a bunch of murmurings for two.
Why two?
What's that?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Oh, OK.
So it won't go below 0, but remember, in version one, the
original correct version didn't go below 0 either.
So remember that this is the correct version.
So let's at least compare the two correct versions.
What's an argument in favor of version
two being, mmm, better?
Yeah?
AUDIENCE: It uses less space.
DAVID J. MALAN: OK, so it uses less space, right?
Whereas version one used 32 bits for n, and then another
32 bits for i.
Version two only uses 32 bits for n, so that
seems to be a plus.
Other thoughts?
Does anyone want to argue in favor of one?
Yeah?
AUDIENCE: You have to use extra line of code for n--.
DAVID J. MALAN: OK, sure.
So that's fair.
So this just, at least to me--
I mean, this actually feels a little messier, the fact that
I can't sort of encapsulate all of my logic in one
beautiful line, the for loop, as the for loop can.
Here, I kind of have to tack on this n--
at the end of the loop, because
it's logically necessary.
But it kind of rubs me the wrong way, just because it
seems separate from the logic of up here, even though,
again, it's necessary.
Other thoughts?
Yeah?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Yeah.
So what if you instead, at the end of the song, wanted to
print out again the name of the song?
Like, "Thanks for playing 99 bottles of beer" or something
silly like that.
But the point is, you wanted access to the original value.
The fact that you've mutated or changed n on every
iteration, and therefore have destroyed its original value,
means you just can't do that at the end.
Now, arguably, we clearly don't want to do
that in this program.
So who cares?
But that's a very valid point.
And to be honest, there's really no one
right answer here.
They're both equally correct.
I could be convinced either way.
I will say that, in general, it's a good principle, if you
asked the user for some value and you stored in a variable
like n, just sort of on principle, it's probably good
to keep that around.
And any data you want to mutate again and again, just
give yourself a copy of that variable, just so that you
have access to the original.
You are spending 32 more bits, but the reality is this
computer has, like, two gigabytes of RAM these days,
and we're quibbling over 32 bits?
Really not such a big deal.
And even on this device here, with a half a gig or a
gigabyte of RAM, 32 bits versus 64 bits,
not such a big deal.
Certainly today, it's going to be way overwhelmed by the size
of the program itself, which is going to be several hundred
kilobytes, if not a few megabytes, these days.
So reasonable concerns, no one right answer.
But at least those are the thoughts that should start to
go through your mind?
Because in pset 0, even though we really only expected
correctness, or at least disclaiming various bugs that
you might have encountered, as we move forward, design is
going to be another key aspect, both of writing code
and also our evaluating code.
And so at least give thought to things like this.
And just because something works doesn't mean it's good,
doesn't mean it's well-designed.
And that's one of the things the teaching fellows and
problem sets will help us tease part over time.
Well, what about, let's say, this version here?
Let me do something a little sexy here in a moment.
First let me get rid of this.
And now let's fix this grammatical issue.
So in this version, I want to fix the grammar so that,
rather than just say parenthetical s, like "bottle"
or "bottles"--
I don't want to cut that corner--
I also want to dynamically print out the word "bottles"
or "bottle," thereby using these %s placeholders today.
So I need to conditionally check what is the value of i.
And if it's 1, I want to say "bottle," and if it's anything
else, I want to say "bottles." so let's try to do this.
So if i == 1, then let me go ahead and declare--
I need a string, so let me do string s1, because it's the
first string I care about right now.
I'm going to say, "bottle." And then, let's see, string
s2-- and I'll explain where I'm going in a moment--
"bottles." So recall that, in this song, we need to be able
to print things, two different words potentially.
So if we look back here, notice that when we get to
this example here, "two bottles of beer on the wall,
two bottles of beer, take one down, pass it around," I want
this fourth line to now say "one bottle of beer on the
wall." So I need to decide, do I want to say "bottles" or
"bottle?" So I'm going to arbitrarily say, all right,
I'm going to now declare a variable called s1, string
one, that's going to get plugged in here and also here,
because those words are always identical, just because of the
nature of the song.
And I'm going to call s2 whatever word I want to
eventually appear down here.
Now, literally, 99 times out of 100, it's going to be the
same in both of those cases, because 3 is plural, 2 is
plural, 4 is plural.
But in this corner case, where we get to 2 and then 1, or
even 1 and then 0, I need this logic.
So I have to spend some time in my code getting that right.
So if I do this, if i == 1, then set s1 equal to "bottle"
and s2 equal to "bottles," because this will be for 1
bottle, and this will be four 0 bottles.
And this here, what does this represent?
Just to be clear.
This is just a comment.
So the fact that you can have single-line comments means you
can comment your code like this, but another common
paradigm, too, is that if you have a super-short phrase that
you want to put yourself, and it's just more readable to put
it right at the end of the line of code, you can
absolutely do something like this.
So now what if I do this? else if i is not equal to 1.
So bang equals--
exclamation point is known as bang.
So bang = 1.
So if i is not equal to 1, what do I instead want to do?
Well, the first word I want to be what?
So string 1 should be "bottles" for plural bottles,
and then this will be plural "bottles" as well, for now.
And we'll see if this actually gets us to
where we want to go.
So now if I scroll down here, notice that I'm plugging in
not only i, but s1.
I'm plugging in i and s1.
And then down here, I'm minus 1, which is the same as
before, but s2.
In other words, I want the English word to change based
on this logic.
Now, there's already some problems in this code.
What is broken already out of the gate here?
Yeah?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Exactly.
So I've already violated the lesson of scope.
So I've declared s1 and s2, but I've done it inside of
curly braces, which means, yeah, this code will work up
until line 42, but as soon as I hit line 43, guess what no
longer exists?
Well, guess what's no longer in scope-- neither s1 or s2.
So we have to fix this.
So let me delete the declarations.
And I'll leave the variable names, and delete this here
and delete this here.
And in what lines should I really declare these things?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Yeah, so probably
right up here, 33-ish.
So string s1 and then string s2.
And it turns out I can do this.
If you're declaring two variables of the same type,
you can actually just use a comma and do that in C. All
right, so now I have two variables--
s1 and s2.
I'm assigning them values in these
conditions here, or in here.
And then I'm using them down below.
How well is this now going to work?
Well, it's still a little buggy, but let's at least see
how far we've gotten.
So let me go ahead and make beer3.
Is this beer3?
Yep, this is beer3.
And now let me go ahead and run beer3.
399 99.
We can probably skip most of them.
And down here, look at that.
"One bottle of beer on the wall, one bottle of beer, take
one down, pass it around, 0 bottles of beer on the wall."
But I'm drawing your attention to only half of the solution.
Kind of screwed up here.
So it seems that the corner cases arise when i equals what
two values?
AUDIENCE: 2, 1.
DAVID J. MALAN: 2 and 1.
It's not 1 and not 1.
It's really just these last two stanzas of this song.
So what do I instead want to do?
So I seem to have caught the case where if i is == to 1,
then the first word is "bottle," but the second word
is "bottles." But here, I want to change this to be == 2.
And if this is the case, what do I want the
first word to be?
AUDIENCE: "Bottles."
DAVID J. MALAN: "Bottles," so for two bottles.
And then this word here should be--
AUDIENCE: "Bottle."
DAVID J. MALAN: "Bottle," singular.
All right, let's zoom out, go back over here, re-run make,
re-run beer3, type 99 again.
OK, "Segmentation fault (core dumped)."
What have I done wrong?
AUDIENCE: You don't have a value [INAUDIBLE].
DAVID J. MALAN: Ah, excellent point.
All right, so what's wrong here?
So segmentation fault, and we're actually going to see
this quite a few times in the future, deliberately.
But for now, what does this actually mean?
A segmentation fault almost always means that you have
somehow tried to access memory, RAM in your computer,
that you don't own, that you have not actually asked the
operating system for.
So in this case, notice what I've done, which is
flawed in my logic.
I have assigned s1 and s2 a value if i equals 1.
I've also done that if i equals 2.
But I haven't done it in the infinite number of other
possibilities--
in particular, 3 or 4 or dot, dot, dot, 99.
So one fix for this could just be, let's
have an else condition.
And let me go in here and say s1 equals--
what should it be here?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: "Bottles," because in the common case,
it's just the same thing.
So equals quote, unquote, "bottles." So for plural
bottles, and then up here, for plural bottles.
OK, so now let me go back to my terminal window,
recompile, re-run it.
99.
Whew.
And let's do a quick sanity check.
Technically, we'd want to read all of these to make sure
they're correct, but let's look at
least the known culprits.
3 bottles, 2 bottles, 2 bottles, 1
bottle, 1 bottle, 0 bottles.
We seem to have at least fixed it for now.
But the catch here is that, what a god awful mess this is
just to solve a stupid
one-character grammatical detail.
So there's kind of a reason that I cut this corner
earlier, because it's just completely annoying to have to
write this much code.
But it turns out that there's slightly more elegant ways of
expressing the exact same thing.
And we can do this as follows.
Let me leave this on the screen for a moment and
introduce something known as a ternary operator.
This is kind of a one-liner that's just meant to make our
lives a little sexier, as promised.
And I'm going to do this as follows.
Give me a string called s1, and let me
assign it as follows.
(i == 1) ?
"bottle," otherwise "bottles." String s2 gets (i == 2) ?
"bottle," otherwise "bottles."
So what then is the difference here?
These two lines of code, I argue, can
replace this whole mess.
So I call it a mess, just because it kind of rubs me the
wrong way, that it's so many lines of code.
Not wrong.
It's not bad design.
Like, this is perfectly correct and perfectly fine.
But coding gets tedious if you have to express yourself so
damn specifically again and again and again with a simple
scenario like this.
So C has some shortcuts, like this.
So this essentially is saying, declare a string called s1 and
assign it either this value or this value if i is ==--
sorry, I should say this more clearly.
Declare a variable s1, assign it this value if this is true.
Otherwise, assign it this value.
So in other words, this is sort of a one-line way of
saying if else, but doing an assignment along the way.
So if i is 1, then go ahead and call this "bottle." And
then this else, call it "bottles." Meanwhile, s2, the
second word that we need to define, if i equals 2, we'll
set s2 to "bottle." Otherwise, set it to "bottles." And what
this means now is I can go through this and delete all of
those lines of code.
And when I say, somewhat ridiculously, that this is now
sexier, it's sexier in the sort of stylistic sense.
The fact that, functionally, this code is actually going to
do the exact same thing.
And even though it might look a little cryptic at first
glance, because we've not seen this construct before, I'd
argue that it's ultimately going to be so much more
readable and so much easier for we humans to sort of
understand, because now you can just read the
code all on one line.
It's still similar in spirit to an if, where this is the
condition, and then this is what's inside the if, and this
is what's inside the else.
But we can do this just much more elegantly.
And if I now go back to my terminal, having deleted all
of those lines and replaced them with just those two,
recompile, re-run bottles of beer with 99, notice that my
grammar is in fact still correct.
So again, something to start.
2 bottles of beer, 1 bottle of beer.
Looks right.
Yeah.
So there we have a much more succinct solution.
So this, too, as you get more comfortable with C, not
necessarily with the first pset or even second, but
realize that these constructs can allow us to do things ever
more elegantly.
Now let's do one other thing here.
Let me go ahead and open up return1.c.
Now let's start to solve another problem in a way that
allows us to write more sophisticated code.
So here's a simple little program whose purpose in life
is to increment values.
And actually, let's take a step back.
Let me do this manually.
Let me do, include and int main(void).
And let me call this increment.c.
And what do I want to do?
I'm going to go ahead and say something like--
will we call the numbers the same--
int x.
So int x gets 2; printf x is %d, new line, x.
So I'm typing fast, but sort of familiar stuff now.
Then I'm going to do x++.
Then I'm going to print that same sentence again.
And then I'm going to return 0 just to quit the program.
All right, so this is a program that
increments a number.
It's first going to initialize something to 2, and then it's
going to increment it and print it again.
So let's run increment, incredibly simple program.
But suppose now that I want to cube the value, so do
something somewhat arbitrary.
And I actually want to do x gets the cube of it.
So I could use what's called the pow function, but I don't
really know where that is yet.
So I'm going to do this the old-fashioned way.
x times this equals x times x times x.
So I'm cubing the value, multiplying it by itself again
and again and again so that we get the power
of 3 in this case.
So now the numbers I should print should be, as we'll see
here-- make increment, so it's actually not really increment
anymore, but we'll leave the name alone--
2 and then 8.
Now, we have the beginnings of an opportunity for refinement
here, whereby this cubing thing of multiplying a number
by itself by itself by itself feel like this might just be
useful to have as a function, much like someone decided
years ago-- you know, kind of useful if one of us sits down
and writes printf so that the rest of the world can use it,
why don't we sit down and write a function called cube
that does this cubing for us so we don't have to manually
implement the notion of cubing values here.
So a simple example, but let's go ahead and use this is as an
opportunity to write our own function.
So thus far, we've only used main, and we've used other
people's functions, but we haven't written our own.
So here we go.
I'm going to go ahead and write a function called cube.
And I'm going to have it take an input.
So it's input is going to be an integer.
And what is it going to do?
It's going to declare int output = input times input
times input.
And then it's going to return that output.
And then I have to be specific now.
This function is going to return an int.
So here then is how you'd write your own functions.
You first decide what's the name of your
function going to be.
And generally, something explanatory is good, so I'll
call it cube.
Then you have to specify what it's going to return, what's
its output going to be.
And we don't have that many options yet.
Int, char, float, bool, string.
For now, I'm going to stick with an int, because I want it
to return an integer.
Then you have to specify what its inputs, if any, are.
And if cube takes an argument, takes something between
parentheses, you have to give that argument a name so that
you can call it something as you're implementing or writing
this function, and you have to give it a type, which in this
case is going to be int.
So in short, cube is a function that takes an integer
as input and returns an integer as output.
So what does it do with that input?
Well, in line 14, I declare a variable called output, and I
assign it the value, input times input times input.
And then I return output.
So how do I use this then?
What do I change these highlighted characters on line
7 to be, do you think?
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: Yeah, so cube of x.
So x is a variable, which means it holds some value.
Fortunately, it's of type integer.
And because x is an int, that means I can pass it into cube.
And even though I'm overriding the value of x with the value
of cube x, as has been the case thus far, any time you
have equal sign and a line of code, the stuff on the right
gets executed and then gets assigned to the
value on the left.
So the order of operations is as we would hope.
So does this work?
Well, let me go down here.
Let me open up my terminal window.
Let me do make increment, Enter.
"Implicit declaration of function 'cube' is invalid in
C99." As an aside, C99 refers to the language C as it was
defined in 1999, which was an update over the version from
1989, which is an update over the original.
So that's all that means.
So what does it mean that "implicit declaration of
function 'cube' is invalid?" It's right here.
It's right there in line 12.
AUDIENCE: [INAUDIBLE].
DAVID J. MALAN: What's that?
AUDIENCE: It's not before.
DAVID J. MALAN: It's not before.
So this is the thing.
C is kind of stupid, or c compilers are kind of stupid.
They really only do what you tell them to do.
And they, in particular, only read your code top to bottom,
left to right.
So if the compiler, Clang, is reading your code, line 1, it
figures out how to do this.
Oh, here comes main.
OK, let me go ahead and declare a variable x.
Let me print something.
Line seven, what the heck is cube?
It's not declared in stdio.h.
It doesn't come with C. I have no idea what to do.
And so Clang just bails and quits with that error message.
So we can fix this in a couple of ways.
We can teach Clang what cube is by just moving where the
declaration is.
So I cut and pasted it atop main.
Now realize that just because main is no longer first, it's
still executed by default.
Main is main.
It's the default function name.
It doesn't matter where it is in a file.
But at least now Clang has seen cube before I use it.
So let's see if Clang is happier now.
Make increment, it did compile this time.
Let me run increment.
And indeed it seems to be working.
Now, you can come up with scenarios eventually where
it's not feasible to put every function
above every other function.
You'll get stuck in this infinite loop in reality,
where this guy wants to be here but this
guy needs to be there.
So that doesn't always work.
So thankfully, C has a more elegant solution.
I'm going to put this back where it was, just because I
prefer, as a matter of principle, that main always be
at the top, because it's just nice to see what this program
does by default.
And what I'm going to do up here is declare what's called
a prototype.
I'm going to re-declare my cube function by literally
copying and pasting.
Actually, that's not literally.
So literally copying and pasting line 15
up above line six.
It doesn't matter what line this ends up on.
It happens to be on line four.
But it does have to be before main.
But notice the difference.
Line four ends with a semicolon, which means, hey,
Clang, take my word for it that there exists a function
called cube that takes an int and returns an int.
But I'm not gonna tell you what it is yet.
Just know that I promise to tell you eventually.
And indeed, now it's OK that this is down below.
So this is generally better, because then at the top of
your file, you can just rattle off, rapid-fire, one line
each, what the names of your functions are, what their
inputs are, what their outputs are.
And to be more clear, input generally means argument or
parameter, synonymous.
Output means return value, what does it a
hand back to me.
So in this case here, cube has been declared at the top, but
defined, otherwise known as implemented, at the bottom.
So now let's go back here and re-run this.
So now let me go ahead and re-run make, re-run increment.
And it now seems to be working just fine.
So now we can go ahead and factor out something like the
beer example into this fourth version.
So let me scroll down here.
And notice that I kind of took this lesson to heart just now.
The fact that I was singing the same stanza again and
again and again, the same chorus line in the song, felt
like, why don't I factor that out into a function?
And indeed, this should be one of the motivations.
Besides the fact that someone else in the world might want
to use a cube function--
that's a good reason to factor something out and write your
own custom function--
if there's a chunk of code in your program that just makes
conceptual sense, that you kind of want to give it a
name-- like in this case, chorus--
then you can similarly write that as a separate function.
You don't have to write everything in main if it just
feels cleaner to separate it out and give it a name.
So in this case here, notice that I have a comment atop
this function that just sings about the
specified numbers of bottles.
Notice here that I don't need to call these
things input and output.
In fact, this time I just called my input b for bottle.
And notice here, void suggests what?
That chorus--
AUDIENCE: Doesn't return it.
DAVID J. MALAN: Doesn't return a value.
And indeed, functions don't have to return values.
They can just do something.
They can have what are called side effects, which in this
case is just a whole bunch of printing on the screen.
So notice that this code here, I literally just stole from
the previous example.
The only difference is, instead of using i as my
variable, I'm now using b as my variable.
So I have b down here, I have b down here, I have b
minus 1 down here.
But the code is exactly the same.
But just to show you now how we can use this, let me go
ahead and actually change this to be a for loop.
for int i gets n; i is greater than n; i--.
So I've stolen that from our previous example.
Previously, it's in line 37 that I would have started
singing this annoying song.
But instead, I'm just going to now call chorus of i.
Done.
So now in every iteration of this loop, I call this other
function, chorus, that I happened to write.
It wasn't written by someone else years ago.
But chorus, meanwhile, uses printf to print
out these four lines.
But the fact that I'm calling chorus again and again in a
loop means that I'm going to get, at the very end, the
exact same song as I have thus far.
So in short, now if I look back at my code, even though
functionally this is equivalent, notice that it's
starting to get even more readable.
I don't exactly know how GetInt.
Is implemented.
Frankly, I don't know how chorus is implemented.
But it doesn't matter to me.
I don't care, because now I can sort of, as a human, read
this from top to bottom.
And because the functions are named according to what they
do, my code is increasingly readable.
And as our programs get much more complex--
by the semester's end, you'll be writing hundreds of lines
of code in languages like PHP and JavaScript and the like--
you'll find that it's so much easier than to keep track of
what you've done.
And when you start collaborating with friends or
partners or colleagues, you'll be able to write much more
massive programs by starting to exercise these basic
building blocks.
So with that said, why don't we call it a day.
And we will see you on Wednesday.
[APPLAUSE]
