[ELECTRONIC STATIC SOUNDS]
ROB: OK, so what we just brought you to is CS50 Spaces.
ALI: Wait, wait back up.
Welcome to section!
ROB: Welcome to section!
ALI: Yay!
ROB: Supersection!
ALI: I'm Ali and this is Rob.
OK, now we'll explain Spaces.
ROB: So what we just brought you to is CS50 Spaces.
You'll be using this a lot in your sections this semester.
Basically, we've already had you download the appliance.
And you can think of CS50 Spaces as a web interface talking to an appliance
that we have on some server somewhere.
So you can run your code in this interface, and we'll
see how to do things.
You can also look at the code of other people in the section, and--
ALI: And as some people have found out, you can chat people on the side.
And we'll all see it, too, so that's exciting.
Come on in, come and sit.
Take a seat.
ROB: So, sections are--
ALI: No, no, you guys can come.
ROB: Sections are going to be much more interactive this semester.
ALI: Oh, he's like--
Oh.
OK, cool.
So if you guys are just coming in, you can go to this link, if I can get
there, right there.
We can't really write it, because there isn't board space, but this link
right here, go to that on your computers, and you'll enter CS50
Spaces, which is a pretty cool thing.
OK.
Do you have a problem?
ROB: So you can find the problems--
we need to be able to write this somewhere.
So if you go to CS50.net/psets and this is the hacker supersection--
and you go into the Hacker Edition of P Set one, look at the specification
somewhere down on page--
ALI: So basically, while Rob's looking, what we're going to do in
section today is, there a section of problems--
ROB: --on page eight.
ALI: --caled a section of problems--
ROB: Section of questions.
ALI: Sorry, a section of questions.
And those are what we're going to go over--
those are what we're going to go over today in section.
And we're going to code it on CS50 Spaces, and hopefully that will work.
And we can just talk through them.
And you guys and ask questions whenever you feel--
ROB: So this is getting to be a common thing with most P Sets.
I think with this one, it says you don't have to hand these questions in.
But the idea is that these questions are put on the P Set, and you can come
to Section to have those questions answered.
Or if you don't come to section, you can answer them on your own, or get
help at office hours or something.
But these are questions are supposed to prep you for the problem set.
And on the hacker edition, a lot of the questions might just be about
expanding your current CS knowledge.
ALI: Yep, pretty much.
OK, so, is everyone on CS50 Spaces?
Hi, come in.
SPEAKER 1: Can we see the URL one more time?
ROB: Yeah, this will be easier once you are actually in your sections, and
your TF can just email you the URL beforehand.
ALI: Yay, take a seat.
There are seats here.
The front isn't that bad.
What?
So, CS50 Spaces, we're getting there.
Does anyone have any questions before we get into-- what?
ROB: There's not even any chalk.
[INAUDIBLE]
ALI: Sorry.
You could use your fingernails?
We're in a very low-tech room for a very high-tech class.
OK, is everyone kind of good?
Does anyone have still questions about it?
As I said before, we're going to go through the section of questions in
the P Set specifications.
So there's just a couple of problems that we're going to
code up in CS50 Spaces.
Is everyone good?
OK.
Good?
ROB: Do you have a laptop?
ALI: You can hang out with Lucas.
He's sitting right next to you.
Bonding time.
ROB: So, start with the first problem?
ALI: Yeah.
We can start.
Do you want me--
I can go.
So, we'll go to the P Set specs.
Oh, why is it--
ROB: Control.
ALI: OK, so are we going into answer these things as well?
ROB: Oh, yeah.
So--
ALI: Oh, did everyone watch Rob's starring shorts?
OK, cool.
ROB: Yeah, I don't think we necessarily expected you to have
watched it before coming to this section, but we can discuss those
problems beforehand, since they are under the section of questions things.
So if you haven't watched it, don't worry.
Those who have can try and answer.
So, the first question, what is a pre-processor, how does #include
relate?
So does anyone have answer for that?
ALI: You guys can talk it out.
Sure, go ahead.
SPEAKER 2: #include  is some pre-written code, and instead of
copying it and pasting it in your program, by just saying include it,
the pre-processor knows that it's there, and that it should add it in
later, or before anything else happens.
ALI: Yeah., awesome.
Cool.
ROB: So when you're actually compiling a program, the pre-processor is this
first step.
Compilation happens in four big steps.
So the pre-processor is the first big one, and it's this guy that goes
through and looks for all of these hash symbols.
And any line that begins with a hash, the pre-processor looks at it and sees
if it can process it.
So #include  tells the pre-processor to look for some cs50.h
file and just copy and paste its contents into this file.
So you can really #include anything you want, but it's mostly going to be
dot h files.
We have not gotten to hash defined yet, so that doesn't matter.
ALI: Yeah, we're good on that one.
Does anyone have any questions about that?
Are we good?
Next question.
SPEAKER 3: In the short there was something about dot c as well?
Is that relevant or is it irrelevant?
ROB: About dot c with a pre-processor?
SPEAKER 3: Yeah, or did I make something up?
ROB: So the short might have been showing pre-processing this file, and
outputting it to another dot c file, so you can pre-process this file--
when you just run like, make hello or Clang hello dot c, you are doing all
the compilation in one big step.
But you can explicitly do it into its separate steps.
So first you can pre-process it.
Then you can compile, then you can assemble, and then you can link.
We'll get to those other ones.
But pre-processing, you kind of pre-process it, and then it goes into
another dot c file.
Because pre-processing doesn't really change anything.
It's just a bunch of copy and pasting.
You could manually copy and paste it yourself.
ALI: And to be clear, the dot c file is a C file, so it's
written in C code.
So it's going from C code to C code.
You're just adding more code with the pound.
ROB: When you pre-processed it, it's still a valid C file.
SPEAKER 3: OK.
ALI: Good question.
I like that.
OK next question.
What's the compiler?
Anyone?
Yes.
SPEAKER 4: It changes the pre-processed code into assembly.
ALI: Perfect.
ROB: Yes.
ALI: Cool.
ROB: So that's what the compiler is doing specifically
when we're using Clang.
In a very general sense, a compiler is just like taking code in one language
and turning it into another language.
So in C--
or, well, Clang is taking code that's in C and transforming it to assembly.
And you don't have to be able to understand the assembly at all.
But that's the language that it's turning it into.
ALI: OK.
And then, what's an assembler?
Anyone?
SPEAKER 5: [INAUDIBLE] to binary?
ALI: Sorry, what?
SPEAKER 5: [INAUDIBLE] to binary?
ROB: Yep.
ALI: Yes.
ROB: So the assembler--
assembly code is really, really close to what your computer can understand,
but remember that it doesn't quite understand the text
that is assembly code.
You need to convert it into straight 1s and 0s.
It's like a direct translation process.
We could just give you a table that maps what each
assembly instruction means.
But the assemblers is just doing this translation for you.
It's transforming the assembly code into ones and zeros.
ALI: And then, for the last one, what's a linker?
And how does -lcs50 relate?
Anyone?
ROB: This is the hardest and least explained one in the compiler video.
ALI: Does anyone remember seeing -lcs50 in a command?
SPEAKER 6: When you went to the make.
ALI: It's in the make.
Yeah, cool, OK.
Is there any guesses or vague-- yes, go.
SPEAKER 7: I'm not sure, because your short was really [INAUDIBLE], was it
something about doing separate files with each library, and then putting
them all together in one library?
ROB: Yes.
So when you have hello.c is a really simple program.
You're really only doing one thing in it.
But when you get into other programs--
and I guess even when you getString in your programs, you need to start
including other files.
So the CS50 library is one such file in which we have the implementations
of getString and getInt and all those things.
So what the linker does is it goes around looking through all of these
files, seeing where functions are defined, making sure that when I call
getString somewhere, it knows that getString means that it's the
getString over in the CS50 library.
So the linker just takes all these files, smashes them together, and now
you have an executable.
So keep in mind, if you're using the CS50 library, you need both the
#include  at the top, and then also in your make command, as you
said, you have to have the -lcs50.
So you can't just have one.
So that's just something to keep in mind for future reference.
SPEAKER 8: So, let's say there was another library, like cs51.h, would we
also have to add -lcs51?
ROB: The only reason this -lcs50 works perfectly is because we have that set
up in a specific place in your appliances so that it knows what
-lcs50 means.
We could just give you a cs50.c file, and then you could compile it, saying
Clang, hello.c, cs50.c, and then it would make your executable by putting
those two files together.
It knows that -lcs50 means cs50.c over in some directory that we specified in
your appliances.
So if you wanted a cs51.c to be specifiable by just saying -lcs51,
then we would also need to put it in that directory so it knows where to
look for it.
ALI: What was your question?
SPEAKER 7: Why do you have to link the CS50?
if, wasn't it copy pasted at the first step when you pre-processed it?
ALI: Do you want to take it?
ROB: Sure.
So the cs50.h file is separate from the cs50.c c file.
Have you gotten to function prototypes in class?
OK.
So basically, the cs50.h file is just going to copy and paste--
ALI: Do you guys know what signatures are?
OK, so pretty much, if you look at--
ROB: Let's pretend cs50.h is not there.
Now this file--
you're doing string s = getString.
But when we've gotten to this point in the code, it has no idea what
getString is.
It knows it's a function, since you're calling it.
But it doesn't know that it's actually supposed to return a string.
So like I said, string s = GetInt, this doesn't make any sense, since
you're signing an integer to a string.
But it doesn't know that getString does make sense, because it doesn't
know that getString returns a string.
So what cs50.h says is something like this.
ALI: So what Rob is typing is, it's a promise in a way that it's going to
have this function called getString.
ROB: This is all that cs50.h is copying and pasting in here, as well
as GetInt and all those things.
And this just says that getString does return a string.
You don't know how it's implemented yet, but when we get to this line, now
it knows that it correctly returns a string.
SPEAKER 9: So if we didn't bother with the include cs50.h thing, and instead
just wrote the prototype for the ones that we are actually going to use?
ROB: Yeah.
So let's run this.
SPEAKER 9: Is it?
So, by default, it would do the -l to CS50 just because [INAUDIBLE]
ROB: --expression.
ALI: Yes, because as you said, it's in the make file.
ROB: cs50.h also happens to be typedef char * to string.
You can completely ignore what that means for now.
But that is also something included in cs50.h.
So now things worked perfectly fine.
It runs exactly the same as it was when we just had
the #include .
And so including cs50.h happens to over-include things you need--
like, you don't use the GetInt in this program, but it doesn't matter.
It'll just ignore it.
ALI: And then when you do the -lcs50 over here and right here, what's going
on is that it's having the actual implementable code.
So that's where it actually is, doing the--
writing the code for getString.
So it's not just a promise anymore.
It is actually going through and taking the string and all that stuff.
Make sense?
Questions All right.
Cool beans.
ROB: Now we can move on to actual code.
ALI: OK.
So here is the first problem.
So it says, write a program that prompts the user for a lowercase
letter and then converts it to uppercase without using bitwise
operations, as per the sample output below.
So you can see, you run the program with the ./a.out, and then you're
going to put in lowercase a, and then your program should give out capital
A. So why don't you guys all give it a shot on CS50 Spaces.
So you guys can all go here.
And you can delete all the code in here.
And then you can go ahead and start coding the thing.
ROB: You'll probably want to use get char, that's
included in the CS50 library.
ALI: I guess it might be better if you save the top part.
So you might want to just change the stuff in the middle.
Go ahead and work.
Feel free to work with each other.
ROB: And you can ask questions if you have--
SPEAKER 10: What is a bitwise operation?
ROB: So, ignore that for this problem.
ALI: If you don't know it, that's good.
ROB: We're going to use it in the next problem.
But if you don't know what a bitwise operator is, that's fine.
SPEAKER 10: Is that like turning it to ASCII code?
ALI: No.
ROB: No.
You can do that for this problem.
SPEAKER 10: How do you do that?
So if only I had somewhere to write--
ALI: Or something to write with.
ROB: I could just kind of type into this.
ALI: Type at the top.
ROB: Oh, I'm sitting on a mic.
So, we saw in lecture, that the ASCII value for capital A is 65.
And capital B will be 66, and so on.
So you can literally use 'A' to mean the number 65.
Like, this is the value 65.
I can do something like, int x = 100 - 'A.' And now x will have the value,
100 minus 65.
ALI: You can run that and show that.
Oh, maybe not.
Never mind.
ROB: I had to print it.
SPEAKER 10: How do you turn it back to character?
ALI: So if you don't--
you just force it to be char A, equals.
ROB: So there is a--
the distinction between a char and an integer is just in terms of size.
So an integer happens to be able to represent things up
to like four billion.
A char is only able to represent things up to 255.
But there is no difference between them other than this.
So you can say, char c equals 65.
That's equivalent to saying char c equals 'A.'
ALI: Oh, no.
It doesn't actually save things.
ROB: No, you can't do that.
ALI: That's just--
[GROANS]
ROB: OK, so what Ali just wrote was a program which first prints 100 minus
'A' as an integer, which was 35, as we expect, because 100 minus the ASCII
value of a is 65.
Then she printed out using %c, which means interpret it as a char.
So 100 minus a is 35.
Interpreting that as a character happens to be the has symbol.
If you look at asciitable.com or whatever, you'll see that 35 is the
hash symbol.
ALI: OK, any other clarifications about the problem?
OK, you guys can go ahead and do it then.
Feel free to ask questions or talk to each other.
Or if you're already done, you can relax.
LUCAS: Are they the same class, all the lowercase letters are order and
also the uppercase are also order, because that's something useful for
the problem.
ALI: Good point, Lucas.
So, did you guys all get that?
SPEAKER 11: Yes.
That's how you do it, right?
ALI: Right.
ROB: Yeah.
SPEAKER 11: [INAUDIBLE]
ALI: All right.
ROB: What is the question asking?
Just to convert--
ALI: Convert the lowercase to the uppercase.
That's it.
ROB: OK
ALI: Should we write it?
I guess we'll just look at someone else's.
ROB: So for those who might be stuck, a way--
if I have some char c, and let's say it happens to be the letter d.
So now how can I figure out what letter of the alphabet c is.
Not d, but I mean, d happens to be the fourth letter of the alphabet.
And if we start counting from 0, then it's the third letter of the alphabet.
So if a is 0, b is 1, c is 2, d is 3, how can I figure out int position--
what position of the alphabet c is in?
Does anyone have any ideas?
ALI: I think they're all coding.
ROB: What about the first one?
SPEAKER 12: So whatever a is, subtract the first one?
ROB: Yeah.
ALI: Yeah, awesome.
So you could do capital D--
oh, sorry.
You take the character and you subtract the first one, as you said.
ROB: So if d is something like 68, and we subtract a, which is 65 then we get
3, telling us that d is the third letter of the alphabet
starting from 0.
So you can use that.
Now we know what letter of the alphabet, in terms of
capital letters, or--
we could do the same thing for lowercase letters to figure out what
lowercase position we're in.
And we can use that to then convert that to uppercase using a
very similar idea.
Ask for suggestions?
ALI: Do you guys-- wait, I don't know how far you guys are.
Are most of you done, are you still working, are you stuck?
You guys can shout out--
stuck.
One person's stuck.
Cool.
I tend to be stuck, too.
SPEAKER 13: I'm done.
ALI: You're done?
OK.
Done.
SPEAKER 13: [INAUDIBLE]
ALI: Yeah, cool.
Are you checking that it's in lowercase form?
OK, cool.
Where are other people?
Did this hint help you, as for un-sticking yourself?
SPEAKER 14: Not really, but just because, I don't know, I'm not
digesting it yet.
ALI: OK cool.
Do you want to try--
or do you want to go and talk?
ROB: What I was going to say is--
so using this.
Do you understand how we got what position of the alphabet
the letter is in?
SPEAKER 14: OK, so when you put things in single quotation a, single
quotation, that returns a number?
ROB: Yes.
It will be translated to the ASCII value it represents.
So do you want to go to ASCII table or whatever it is?
ALI: Just one of these?
ROB: Yep.
So when you put any of these symbols, ignoring a lot of the--
ALI: [INAUDIBLE]
ROB: Oh, using the cursor.
ALI: Yeah.
That was exciting.
ROB: So, ignoring these ones on the left, which are special symbols--
if you put any of these symbols in single quotes, then it will be
translated to this value on the left.
ALI: This is the decimal number for it.
It's like, a matches with 65, b to 66, and you'll notice that they're all in
alphabetical order, which makes a difference.
So, as Rob says, before, in that code, we were calculating the distance from
the first letter, per se.
And that'll be the same, whether it's uppercase or lowercase.
ROB: So when we did d, 68 minus a, 65, we get three.
Because d is three positions into the alphabet.
ALI: So then how would you translate that over to find the little d?
ROB: Yeah.
So if I have three now, I know I want to go three letters into the--
we happen to be going lowercase now, but let's say I want to go three
positions into the lowercase side of things.
So how can I do that?
I know lowercase a is 97.
So how do I find three positions into the lowercase letters?
SPEAKER 15: I have one question actually.
ALI: Yeah, go ahead.
SPEAKER 15: So for this, it doesn't really matter if I know this position,
like, I don't need this table.
ROB: Nope.
You will never need to use any of these numbers.
And this is an important point in your programs that you should never hard
code any of these constants.
Use 'A.' never use 65 or 97.
ALI: Those are called magic numbers, and they're really confusing.
Like, when you're debugging a code, you might not remember what
you used them for.
And for us grading your code, we won't really know what
you're using them for.
So it's better if you actually use the characters so it makes
more sense to people.
OK, any other questions?
Are more people done, or--
I guess We can check.
It's really creepy that you can see people's code.
ROB: Yeah.
We don't have to do that here.
We don't know people's names, either.
ALI: Oh yeah, well that makes it better, so we'll be even more unbiased
instead of just randomly picking someone.
Don't worry.
I won't do it.
If you have random things about-- never mind.
OK.
How are people doing?
SPEAKER 17: So the ninth line should print out a character?
ROB: Yes.
ALI: Yeah.
So if you go down--
ROB: Oh, can't do that.
ALI: You'll see that it printed the hash symbol.
SPEAKER 17: Oh, OK.
ROB: I guess another way you can look at things is, we're printing two
characters.
First one we're printing is the letter a.
The next one we're printing is just 65.
It'll probably yell at me for these.
So if we just run this, you'll notice that it prints A both times.
Because we're asking it the same thing.
We're asking it to print the letter A. And then we're asking it to print the
number 65 interpreted as a character, which is the same thing.
ALI: Do you have something to say?
Oh, just kidding, sorry.
All right, how are people--
ROB: We can just walk through it.
ALI: OK, so how do you start?
Anyone?
As a hint, we have to get something from the people, from the typers.
SPEAKER 18: [INAUDIBLE]
ALI: Oh yeah, a prompt, perfect.
So we'll type--
what do we type?
Anyone?
Or should i just type it?
Are we actually typing the--
ROB: Sure.
ALI: So we'll type a printf to prompt it, so we can be
like, give me a character.
OK, and then what?
Why is it doing that?
ROB: I don't know.
ALI: OK.
So now, we're telling them to give us a character.
But then how do you actually get that character?
SPEAKER 19: Use getString.
ALI: GetString?
GetChar?
OK, so what's the difference between a string and a char?
SPEAKER 19: Strings are a series, like an array of characters.
ALI: Cool, yeah.
So in this problem, we only need to consider one character at a time, so
we're only going to do getChar for that instance.
ROB: We could implement a function if we wanted that took an entire string,
and went over the string and changed all lowercase to uppercase and all
uppercase to lowercase.
But here, we're just asking you for one character.
ALI: So now we have the character here, but then we need to save it.
So then we'll add char c-- what?
SPEAKER 20: Define the variable.
ALI: Yeah, exactly.
So we have our character.
ROB: I think you might be--
you're only three spaces in, which is why it's yelling at you.
ALI: OK, cool, now that we have tabbing set, what happens next?
What's the next step?
ROB: What our program should do is change a lowercase letter to an
uppercase letter.
What if I happen to enter the hash symbol?
Is that--
ALI: It's a good symbol.
We use it a lot.
ROB: Is that a valid thing I can convert to an uppercase form?
SPEAKER 21: No.
ALI: No.
We should check that.
So we can have an if statement checking so if the c is greater than
or equal to the lowercase 'a'--
so if we look at the chart, you'll notice that it has to be between here,
at 97, and the lowercase a.
And it can be any of these, and in increments all the way down.
And then there's z at 122.
And it has to fall between these two values.
Does that make sense?
ROB: So if c is not between 97 and 122--
or you should never need to use those numbers-- if c is not between 'a' and
'z,' then it wasn't a valid character for us to uppercase.
ALI: So in code form, we say that if c is greater than or equal to single
case lowercase--
wow, how did you say that.
OK, is greater than equal the lowercase 'a,' and it has to be above
the lowercase 'z.' So it has to be less than equal to lowercase 'z.'
We're making sure it's between the two.
Then we can continue on with our happy code.
What?
ROB: So I figured we would just keep asking, if we happen to not have a
lower case letter.
ALI: Oh, I wasn't aware of that.
Sorry.
OK, so if we're going to do as Rob says, and make sure that--
we can keep asking them, then what should we do?
SPEAKER 22: [INAUDIBLE]
ROB: Yeah.
We should use some sort of loop.
Because the user can enter something invalid an untold amount of times.
So you can use a while loop.
The purpose of a do while loop--
literally, the only time in your entire lives you will ever use do
while loops is when you're asking for user input.
So the fact we're asking for user input here is a hint that we should
use a do while loop.
And why is that?
Because do while loop always happens at least once.
So when you're asking for user input, you want that to happen at least once.
And then if things were successful, you can keep going.
If not, go back and ask again.
ALI: So in other words, we have to do section.
And so this is telling it to do something.
So printf--
print the statement, the prompt, and also get the character, or attempt to
get a character.
And then we have to check if it actually did it correctly.
So then we add the conditions, then we say while, and then we have the
conditional statement.
ROB: But now we have reversed the train of thought.
Now we originally were saying, if c is in this range, it is valid.
Now we want to reverse that and say, if c is not in this range, then we
need to back to do things again.
ALI: Oh, yeah.
ROB: So while this is not true, we want to go back and
ask for another character.
Does everyone see that?
Questions on this?
OK.
So now we have a valid character that we can uppercase.
ALI: So then what the next step for uppercasing it?
SPEAKER 23: Add 32.
ALI: You add--
sorry, what?
SPEAKER 23: Can't you just add 32?
ROB: So yes, not in terms of magic numbers.
You should only be using single quote stuff.
SPEAKER 23: OK, well--
ROB: But you can get 32--
ALI: How did you get the number 32, I guess, is what we're saying.
SPEAKER 23: [INAUDIBLE]
ROB: So we can come up with the number 32 together--
SPEAKER 23: [INAUDIBLE]?
ROB: Yeah.
But if we're going to do it in the two steps we did before with
the position stuff.
So the position in the alphabet that c happens to be is c minus lowercase
'a.' So if we entered a lowercase 'd,' position is going to be 3.
And now we want to take things to the uppercase range of things.
So now our new c is going to be the capital 'A' plus position.
So do people see how that brings us--
we're moving from the lowercase range, the exact depth we were into that
range, and going down into the uppercase range, and going that far
into it again, which is going to be the same character, but now
uppercased.
ALI: And for the people that were confused by how he just said 32,
basically he combined both of these into one statement.
So an equivalent way of writing this to say, you can just kind of
substitute position, the c minus 'a,' and put it right here.
So what he did, I don't--
char newc = uppercase 'A' plus c minus lowercase 'a.' And because of algebra
you can move them around.
You can also say that you can move it around so chart newc = uppercase 'A'
minus lowercase 'a' plus c.
And this, you'll notice if we go back to the chart.
We have uppercase A is 65 and lowercase a is 97.
So 65 minus 97 is negative 32.
Hi.
Take a seat.
Oh.
You can sit right here.
Cool, OK, awesome.
Welcome to Section.
You'll notice that the difference is 32.
So that's where he got that number.
But it's not, as Rob says, the best way to do it, because it has the weird
magic number confusion.
ROB: You should use capital a minus lowercase a.
You should not use just straight 32.
SPEAKER 24: Why is that, again?
Why should you not use 32?
ALI: If we did it, it would be, char newc = negative 32 plus c.
And if you don't see any of the rest of it, if this is all gone, and you
just see this single line, then how do you know what the negative 32 is?
It's just out of place.
ROB: So your program would work completely fine.
It's just a style thing.
Someone going in and reading your code, they're like what does 32 mean?
Maybe they don't--
I probably would not immediately realize that 32 happens to be
difference between a lowercase letter and an uppercase letter, although
we're going to use that fact in the next problem.
32 is--
you could leave a comment above it saying 32 is the difference between
'A' and 'a.' But at that point, why not just use 'A' and 'a,' and you
don't need the comment then.
ALI: It's just the ways above it a lot cleaner, style-wise.
And so, since you're just starting programming--
or I guess not, since you're hacker edi-- never mind.
It's just a good way to have--
it's better to have better style.
It's easier for other people to read.
ROB: You should never need to remember the ASCII table, ever.
You should just be able to use the single quote characters.
Questions?
ALI: Everyone good?
ROB: OK.
So the next problem is substantial.
So the next problem asks us--
ALI: The next problem is asking for us to do the same thing, but to use
bitwise operators.
ROB: And of course, we have not seen bitwise operators yet.
So we'll now discuss those.
ALI: Be excited.
They're super fun.
ROB: So the regular operators, like x plus y minus, times, divide.
ALI: Type it in this prompt.
ROB: There's also %, if you haven't seen it, which you can use by the
percent symbol.
But we won't use those for this problem.
We want to use bitwise operators.
Now remember, we brought it up in lecture one.
I'm not sure if we've discussed binary beyond that.
But remember that every single number is represented--
well, everything--
is represented in 1s and 0s in binary.
So that means that when I say the number 8, I happen to know that that's
like, 1000.
What bitwise operators let us do, is operate on these bits--
is operate on these bits directly.
Now I'm no longer dealing in terms of eight.
I'm dealing in terms of 1000, and I want to do things with those
individual bits.
So Ali has written the bitwise operators here, but that's--
The number 8 we'll use as one of our example numbers.
And the binary representation is 1000.
We'll use another number, 5--
actually let's use 9 and 5.
And the 5's binary representation is 00--
0101.
ALI: Is everyone good on that?
The binary stuff?
It was from the first lecture?
ROB: So even if you aren't entirely on top of how to convert things to
binary, that's not entirely important for this problem.
We'll be using it, but you'll have many more chances to figure out how to
quickly turn things into binary.
So using 9 and 5, now we have our bitwise operators.
Oh, and also, 9 and 5, if it's an integer, then really it's 32 bits,
which means we have like 0, 0, 0, 0 a lot of times, then
101 on the very end.
That's just because, no matter what you do, in integers, 32 bits.
Just because we only need four bits to represent 9 doesn't mean we're not
using up the other 27 bits for just 0s.
ALI: Just to clarify, one of these numbers that's a 0 or a 1 is a bit.
This one is 4 bits.
As so Rob said that machines store them in 32.
So then they would have 32 of either a 0 or a 1.
Cool?
ROB: The bitwise operators.
The first one that we'll deal with, let's do &.
So if we do 9 & 5.
So what & does is bit by bit, it compares the bits of the two numbers.
And this if both of the numbers are is 1, then it will return a 1.
If one is a 0 and the other is a 1, or both are 0s, then it returns a 0.
So you can think of it as your logical ands.
Like you need true and true to return true, but true and false is false.
So it's the same thing, but now we're dealing with it with just bits.
ALI: So if you look at this, you'll have 1--
you'll line them up, so it'll be 1 and 0.
Do you guys think that would be-- what would that evaluate to?
SPEAKER 25: 1.
ALI: Cool.
Or no.
Sorry.
So does that makes sense?
So what is the collective answer again?
Sorry.
So if we have 1 and 0, then what do you get?
ROB: So you think of how you say and out loud.
If you have two bits, x and y, you need x and y to be 1 in order for it
to evaluate to true-- or, in order for it to evaluate to 1.
If x or y are 0, then it evaluates to false or 0.
LUCAS: It's good to remember also that 1 is true and 0 is false.
So if you have true and false, it's false.
But then, true and true, true.
False and false, false.
ALI: We have true and false.
So 1 and 0.
So then again, sorry, one more time?
SPEAKER 25: It would be 0.
Yeah, cool.
And then we have 0 and 1--
SPEAKER 25: [INAUDIBLE]
ALI: Yeah.
So you can always swap them in--
& Then if you have 0 and 0?
SPEAKER 4: 1?
0?
ROB: So it's 0.
It's not that both numbers have to be the same.
It's that both numbers need to be 1.
ALI: So both have to be true for it to be true.
So that's 0.
And then you have 1 and 1 which is?
ROB: These are pretty good numbers.
They have all possible--
ALI: Good work, wow.
OK, cool.
So does that make sense to everyone?
ROB: So now we'll do |.
And this is going to be very similar, but now instead of x and y needing to
be 1 in order for it to evaluate to one, now it's just x or
y needs to be 1.
ALI: So 1 or 0 evaluates to--
CLASS: 1.
ALI: Cool.
0 or 1 evaluates to--
CLASS: 1.
ALI: Cool, and then 0 or 0--
CLASS: 0.
ALI: Yeah, and then 1 or 1--
CLASS: 1.
ALI: Cool.
So that's like two bitwise operators.
Awesome.
ROB: So now we'll do ^.
ALI: Should we do all of them?
ROB: Yeah, because I think we're going to use it--
using them all.
ALI: OK.
So--
ROB: I guess we don't need to.
ALI: So ^ works in that, you have to have exactly one true and one false.
^ means exclusive or.
So now it's not--
if x and y are both 1, it's now false.
That is the difference between ^ and or, is that or, you can have, if x is
true or y is true, then we're good.
No, ^ says if x is true, y must be false, or else it's not true.
Do you have a question?
SPEAKER 26: [INAUDIBLE]
ALI: Yeah.
It's kind of similar.
ROB: Yeah, so when you get to that low-level hardware stuff, these are
the types of operations you're dealing with.
At the hardware level, you will only deal with bits.
You don't deal with numbers.
ALI: OK, for ^, or if you have 1 ^ 0, what should that evaluate to?
CLASS: 1.
ALI: Cool.
If you have
0 ^ 1 CLASS: 1.
ALI: Cool.
0 ^ 0?
Cool.
And then 1 ^ 1?
CLASS: 0.
ALI: Cool, awesome.
The next one--
ROB: I think these are all we have to deal with.
We'll only do these.
ALI: The only time we'll have to do--
ROB: Oh, that will be for the last problem.
SPEAKER 27: Wait, once again?
ALI: Sorry, what was your question?
SPEAKER 27: Can you explain that once again?
The ^?
SPEAKER 27: Exclus-- yeah.
ALI: So what the exclusive or means, is that there has to be exclusively
one true and one false, so one 1 and one 0, versus with or, you can have--
one of them has to be true, or both of them can be true, for it
to evaluate to true.
SPEAKER 27: So 0 and 0 would be false.
ALI: Yeah.
But if you have 1 |
1, that would evaluate to true.
But if you have 1 ^ 1, as we did, that evaluates to false.
Because it's not exclusively one is true.
ROB: And this may or may not be helpful, but notice that the ^ is
equal to just taking the |
minus the &.
And you can actually think of it this way.
^ is just or'ing everything together, but taking out any of the bits where
both were true.
So & returns everything where both were true.
| returns everything where one or both were true.
So subtracting that out from the | gives you the ^.
ALI: Any questions?
This was a lot of information.
Everyone good?
ROB: We can go over the next ones for the next problem slash
what time is it?
They don't need this until the next problem.
ALI: I thought it was this one.
ROB: It's not.
ALI: Are you sure?
ROB: Yes, I'm positive.
ALI: Why don't we start doing the next problem.
The problem is, again, to change it from lowercase to uppercase, and this
time to use bitwise operators.
ROB: So we will--
let's start with the binary representation of 'A,' capital 'A,'
which is 65.
So in binary--
so 'A' = 65, which =, in binary--
I'm going to mess up the number of 0's-- that.
ALI: So does that make sense to everyone?
So, 1, no 2s, no 4s, no 8s, no--
no 16s, no 32s, and then one 64.
ROB: Yeah, I think that's one too many 0s.
ALI: Sorry.
ROB: OK, so we have the 64 set, and we have the 1 set, and combining those
together, we get 65.
ALI: Cool beans?
ROB: So now, lowercase 'a'--
notice 97--
what is the difference between 97 and 65?
SPEAKER 28: [INAUDIBLE]
ROB: Yeah.
So it's 32, which is its own bit, so that's going to be 110001.
And this is going to be true for all possible characters.
So if we think of 'D,' which is going to be 68, that's going to be 1000011.
And then lowercase 'd' is going to be 68 plus 32, which is 100, which is
going to be the same thing that this was, just flipping the
32 again so, 1100011.
So the difference between an uppercase and lowercase letter is just flipping
that 32 bit position.
SPEAKER 29: Isn't it 1000100?
ROB: Wait, it's 100--
something I did wrong.
This was not true.
I was thinking that it was a difference of 3, so then I just stuck
the binary 3 at the end.
This should be right.
ALI: Thank you.
Good for pointing that out.
That was sharp.
All right, is that clear to people?
ROB: The difference between the uppercase and lowercase version is
always just going to be 32, and so it's always going to be a single bit
that needs to be flipped to change between the two.
ALI: So in that case, knowing the difference between the capital A and
the lowercase a is a good thing.
Not in your code, but conceptually at least, it's good.
So you guys can go ahead and code that in Spaces now.
Or should we just discuss it?
ROB: We can just discuss it.
I don't know.
You guys can try.
Talk amongst yourself for a bit.
We'll give you a chance to code it.
[INTERPOSING VOICES]
ALI: --is cool
SPEAKER 30: This is like hacker comedy.
ALI: Yeah, we're just telling the news, going through it.
ROB: And we're back.
ALI: That's kind of weird.
I feel like we should have a CS50 news station and we could
actually sit like this.
ROB: Hacker News.
ALI: Hacker News 50.
ALI: Feel free to ask any questions if you're confused.
ROB: Is anyone stuck?
ALI: Yeah, that's a good thing.
ALI: Wait, are you stuck in your chair?
Oh.
I was a little concerned.
ROB: Because I just realized that we are going to want
another bitwise operator.
For now, let's just convert uppercase to lowercase.
ALI: Sorry, did everyone get that announcement?
We're going to go from uppercase to lowercase.
ROB: Then we'll discuss lowercase to uppercase right after that.
Oh, no.
We have a bug in this, which, I guess, we never tried to run.
Which is just that char c needs to be declared outside of the loop, because
its scope is restricted in the loop.
SPEAKER 32: In this case, is it wrong to use a number?
ROB: Eh, you don't need to.
If I guaranteed you that capital 'A'-- or, lowercase 'a' minus capital 'A'
was exactly one bit, but that you don't know it's 32--
things would work just as well if it were the 16 bit that was flipped-- or
no, I guess it wouldn't--
or the 64 bit were flipped, possibly.
But you shouldn't need to use 32.
You could instead use lowercase 'a' minus capital 'A.'
SPEAKER 32: OK.
What you can do you feel like you're writing too much, is you can define it
at the top.
So you can be like, int difference = lowercase 'a' minus capital 'A.' And
then you can type difference instead.
That's valid.
But just using the number 32 is kind of--
SPEAKER 33: Even though it's because of the fact that it's the 32 bit?
ALI: Yeah.
ROB: There could be--
the only guarantee we need to make you is that the difference between the
lowercase and uppercase is one bit.
It shouldn't matter that it happens to be the 32 bit that's flipped.
For time considerations, we'll start going over this.
It's OK if you haven't finished.
Don't worry about it.
ROB: Assuming c is a capital letter--
we don't have to assume c is a capital letter.
We know c is a capital letter after this while loop--
do while loop.
So that means it looks something like this 'A.' So if we want to bring this
'A' to this 'a,' what do we need to do?
So how do we convert and flip the bit?
ALI: How do we flip it?
ROB: So we know we want to flip the 32 bit.
So that will do 'a' minus 'A,' or we could write 32, but--
darn it, it's the other way around.
ALI: OK so Rob years calculating magic number 32.
So he's finding out where that bit flip area would be.
And then what do we put where the question marks are?
ROB: How do we flip that bit?
In terms of the uppercase letter, it is a 0, and we want to become a 1.
SPEAKER 34: |.
ROB: Yeah.
So this is us saying, we take 'A.' We're or-ing it with 0--
1000--
and that = that.
ALI: Does that make sense to everyone?
We can go through it bit by bit if you want.
SPEAKER 35: Are you [INAUDIBLE]
ALI: Where's the minus sign?
ROB: Oh, you mean in here?
ALI: Oh, yeah.
ROB: So I guess this is us.
We could say 32, and now we're just using bitwise operators.
ALI: We don't like magic numbers.
We're not going to do that.
Also I think we should just use a bitwise operator--
SPEAKER 36: If you use a ^ A, will you get 32?
SPEAKER 37: Yeah, I think--
ROB: Yeah you will.
ALI: This is how you would have done it for going
from capital to lowercase.
Now can anyone tell me why Rob and I changed the prompt and how we went
from uppercase lowercase, instead of lowercase to
uppercase as we did before?
Does anyone have any ideas why that might be more difficult?
ROB: So we'd do--
ALI: Yeah, go ahead.
SPEAKER 38: The | operator was only really good for adding.
ALI: Yeah, exactly.
ROB: So what we want to do in the lowercase to uppercase case is,
convert this 'a'--
so we want to put in some numbers here and use some operator so that it comes
out to capital A. We're still probably using 32 somehow, but now how do we
get this to come out to this?
So c--
oh, I still want that too--
ALI: So now if we're converting from lowercase to uppercase again, then we
do the ^ operation, as you guys said.
ROB: There are other ways you can do things.
A lot of the bitwise operators end up being very easily definable in terms
of other bitwise operators.
So I was going to not use ^ or at all, but ^ worked perfectly fine.
ALI: OK, so we're going to go at the last problem, which is to basic--
the last problem is to convert something into binary.
So for instance you have 50, and then you convert it to
binary, which is 110010.
And I think you guys all know about binary from lecture.
And you also are not supposed to put any leading 0s into it.
ROB: You can ignore that part for now.
The first pass, you can do it so that there are leading 0s.
And then we can modify that to have no leading 0s, if we have time.
ALI: So don't worry about that.
Just try to get in binary.
A good place to start would be--
ROB: We need to ask for an integer.
ALI: Oh yeah, that's a good one.
We can start with that.
So you can change the prompt.
So instead of a character, now we're dealing with integers.
Cool?
ROB: And now what is our do while condition going to be?
It's asking for a non-negative integer.
ALI: When do we want to keep prompting the user for something else?
When it's smaller than 0.
ALI: Right.
ROB: While i is less than 0.
ALI: Now we want to convert it.
To you guys have any ideas of what to do?
Any inklings?
Yeah.
SPEAKER 39: Do we have to convert it, or can we just print some 0s and 1s
that would be the right number?
Could you do a for loop and count out by powers of 2?
ROB: Yes.
You don't need to convert i to its binary--
the binary representation of i will not fit inside of i.
You just need to print the binary representation of i.
ALI: In other words, you do not need to go by powers of two.
ROB: Because i is already being stored as binaries, so you don't need to
convert it to binary.
Just go over its binary, and print it.
And you're going to need to use bitwise, because you want to look at
the actual bits.
You don't need to use bitwise, but please do.
And that's actually--
you can powers of two by multiplying by 2.
We'll go over one of the last two binary bitwise was operators,
which is this one.
So when you take--
ALI: Can you go through both of them?
ROB: Yeah.
So let's go with 9.
So 9 left shift 1--
what left shift means is just move all the bits to the left and insert a 0.
So we're moving all the bits of 9 to the left one
position, which gives us--
So notice we have shifted everything left one, and inserted a 0 on the
right side.
If we had shifted left by two, we would shift everything left by two,
and insert two 0s to fill in the gaps.
Question?
ALI: So then right shift does a similar thing.
If you have 9 right shift 1 then you're just moving everything over to
the right, you lose a digit, so 100 instead.
ROB: So you it's fine that you are losing the bit that happened to be all
the way to the right.
There are different types of right shifts, but basically you can think of
right shift as just dividing by 2.
And you can think of left shift as multiplying by 2.
So if you converted this--
if you converted 9 shift 1, which is equal to 10010, if you actually went
through the binary and figured out what that was, it would just be 18.
We just multiply by 2.
1001 left shift 2 is going to be 36.
We multiply by 4.
OK, cool, so that's a handy bitwise operator for this one.
More confusion?
Do you guys want to try it out?
Or we can just jump right in and start it?
ROB: We should probably jump right in.
ALI: Yeah, OK.
ROB: And walk through it together.
ALI: Well I'll just go into it.
So as he said in the beginning, we're going to just go through bit by bit.
So we're going to need a loop.
Does anyone have an idea of the best kind of loop to go through this?
We have while loops, do while loops, for loops.
SPEAKER 40: Do while loop?
ROB: So remember what I said before about, we are only using do while
loops to get user input.
You will never pretty much ever use them for anything else.
ALI: The problem with do while loops, is it does something before checks for
the condition.
So, it could do something bad--
like, hurt--
do something that's not possible.
So yo want to check first.
ROB: There's a lot of cases where you can use do while loops, but people
don't expect you to use them unless it's user input.
So we have used our do while loop to get i.
How many times is our loop going to want to loop?
We want to loop over each of the bits of i.
How many bits are in i?
SPEAKER 41: 32.
ALI: Yeah.
ROB: So there are 32 bits.
We don't want to say 32.
We instead want to say, sizeof--
which, have you seen that in class yet?
ALI: Nope.
ROB: Why does it say to use that--
sizeof(int) times 8--
ALI: So, sizeof is--
SPEAKER 42: [INAUDIBLE]
ALI: Interesting.
So, sizeof is a built-in C function where it just tells you the
number of bits in--
ROB: Bytes.
ALI: Bytes, sorry--
the number of bytes that a variable has to store a value.
So I think he went over in class than an int is 4 bytes maybe.
Cool?
ROB: But you shouldn't need to know that an int is 4 bytes.
You should be able to say--
you should use sizeof int to get 4 bytes.
And that's actually important for some things.
An int might not be four bytes.
On another computer, an int might be 8 bytes.
So your program won't work on that computer because you hard-coded 32
bits when on that computer happens to be 64 bits.
ALI: So you have the total number of bits that you want it to reverse.
ROB: And the difference between a byte and a bit is that there
are 8 bits in a byte.
So sizeof(int) returns 4 bytes, then we have to multiply that
by 8 to get 32 bits.
ALI: OK, so we know the maximum and we know we want to go from--
we want to go through all of them.
So we want to go from 0 to numBits.
So does anyone know how to write the loop for that?
Anyone?
SPEAKER 43: [INAUDIBLE]
ALI: So you want to traverse the number i from the zero-th bit to the
first bit, the second bit, the third bit, all the way to numBits.
The max number of bits that you can get to.
ROB: What's the common loop we use what we want to do something x times.
ALI: For.
Perfect.
So we have for.
And then we'll create an iterator, which is not going to be i.
ROB: j.
ALI: J equals 0.
So we'll start at 0.
And then we're going to have the condition to make sure, while you're
going through it every single time--
[INTERPOSING VOICES]
ROB: j.
ALI: j is less than numBits.
So we don't want to do the actual equals one, because they're numBits
total, and we start at 0.
So we're actually going to have--
SPEAKER 44: Oh.
ALI: The indexes don't end at numBits minus 1.
ROB: We label the bits 0 to 31, we don't label them 1 to 32.
ALI: And then we're going increment each time by one, because we want to
check every single one.
So we'll go j++.
SPEAKER 45: Why are you doing that?
SPEAKER 46: Why are you going through every bit?
ROB: So we want to go through every bit and--
So let's say we have some number.
ALI: 68.
ROB: We can use 68.
So the binary's going to be 100100.
So this is inside of i and we want to go over each of these bits.
Is it a 1?
Print 1.
Is a 0?
Print 0.
Then we go on to the next bit.
Is it a 1?
Print 1.
Is a 0?
Print 0.
ALI: Cook, OK.
Now we're at the correct index for where that bit is.
How can we check that specific one?
Let's say we're at j = 0, so we want to check the 0 index of the bit.
So, in this case, this one.
So now how do we go about check-- oh, it would be this one.
ROB: Yeah.
ALI: Sorry.
How would we go about checking that one, in a sense?
How would we check if it's a 0 or a 1?
Well let's--
CLASS: And 1?
ALI: And?
Yeah.
ROB: So let's say we already have 1.
Then this & this will return whether it was a 1 or a 0.
ALI: So we can go down.
And we can do as you guys said, of doing the & function.
ROB: int--
how do I want to say this--
isOne = i.
And for the first bit we happen to be looking at, we're doing i & 1.
Now what are we going to want to & by for the second bit?
SPEAKER 47: 2.
ROB: Yeah, the second that we're on 2.
ALI: You'll notice that the 1 has moved over to the left one.
So have we learned any bitwise operators to do that function?
ROB: The next one--
ALI: Yeah, right, exactly.
So it's a left shift.
Instead of always checking with 1, we're going to shift it.
And how many times are we going to shift it?
If we're checking the 0th one then we're going to move it over zero.
Yeah, exactly.
So you left shift it by j.
Perfect.
So now we know--
we have this int of if it's 1, and then--
so Rob's kind of cheating here--
and so now he was going ahead and he's just saying that if it actually is 1,
because 1 evaluates to true, so we don't have to say is isOne equals 1--
so if isOne, then we print 1, and otherwise we print 0.
ROB: So our program has an overall bug.
Well, questions on this first.
SPEAKER 48: Can you ever put the isOne inside the four operation part and
then have it shift itself as the last part?
So isOne equals 1 and then--
ROB: Yes, you can.
We can actually show that once we fix the bug that I'm about to
discuss with you all.
Notice the order we're going over things.
Given this binary representation, we are starting with the 0th bit.
If it is a 0, then we are printing--
well, it is a 0, so we are printing 0.
Then we go to the second bit.
It is a 0, so we print 0.
Then we go to the third bit.
It is a 1, so we print 1.
ALI: So it's going backwards.
So how do you guys suggest that we fix that and go the other way?
SPEAKER 49: [INAUDIBLE]
ROB: Yeah.
So instead of going from 0 to numBits, we'll go from numBits bits to 0.
ALI: So [INAUDIBLE]
can always go the other way.
ROB: NumBits minus 1, because that's the last nubmer--
ALI: Because it goes from 0 to 31.
And then we'll always make sure that it's greater than 0 so you don't go
too far to the right.
And then you'll always subtract by 1 to go to the right.
ROB: So now we have a reverse loop, and the number is back into printing
in the correct way.
SPEAKER 50: Don't you have to change the shift thing too?
ALI: So no.
ROB: We're doing the same exact operations, except now
in the reverse order.
So instead of doing the shifting by numBits minus 1 to get whatever this
bit is, instead of doing that last, we'll just do it first.
By reversing this up here, we reverse the order of everything
that happens inside.
But we don't want to change what happens inside at all.
ALI: Does that make sense?
Processing?
OK, so does anyone else have any other conceptual questions?
ALI: Before we go into his point which is--
ALI: All right, well go.
ROB: Instead of using j to be our--
instead of using j to always shift by, like one left shift j, I think what
you're saying is like, to j use itself.
So for j--
I guess this is the hard-- j = 1 left shift 31.
Is that what I want?
I think it's left shift 31.
j is greater than or equal to 1.
j right shift, right shift isOne, i & j--
so now instead of using--
ALI: You're constantly moving j instead of having an
index to check it.
It's not that bad.
We're using a similar kind of logic.
So if you go back--
oh, but it's going to lose it.
OK, you're just going to type it again.
If you notice that we have 1 left shift j amount of times, and we were
incrementing j every single time by one increment, but this time instead
they're doing the increment of j at the top inside the for loop.
So instead of always moving it down--
ROB: The very first iteration of for loop, we have j is 10000.
The next iteration of the for loop is 01000.
The next iteration is that.
And the 1 is just going to keep propagating down until we hit the very
end where now it's this.
The next one, the 1 is going to be pushed off, and j is no longer greater
than or equal to 1.
I could also put greater than 0, same difference.
And then that's it.
Questions?
Yeah.
SPEAKER 51: [INAUDIBLE]
ROB: So that's the same as--
have you seen j += 3?
So this is the same as j = J + 3?
You can do that for virtually any operator in C. So j right shift = 3 is
equal to j = j right shift 3.
So that works also with bitwise operators.
And I should not have put 31 here.
I should have put numBits minus 1.
ALI: Yay, no magic numbers.
OK, it's 4:00 though, so if you guys have to go-- but does this make sense?
Do you guys have any other questions?
ROB: I was also going to throw in that if we wanted--
has he discussed ternary operator at all?
ALI: No.
It's OK.
ROB: So you could look into it for next time.
ALI: OK, really?
Now you're just showing off.
ROB: No, now it's--
this is what gets people interested, and now they'll go look into it.
So now, that does the same thing, in one step.
So first check, is i & j 1?
Is it true?
If so, print a 1, else, print a 0.
ALI: But doing it the other way is perfectly fine as well.
It has the same logic.
So it's not like one is--
ROB: At this point, we can get rid of those curly braces, because it's only
a one-line for loop.
ALI: OK, so does that make sense?
That was kind of a jump.
But it was just kind of syntax, more so.
Cool?
Any other questions?
ROB: All right.
ALI: All right, cool.
Thanks for coming to Section.
