 Welcome back to 105. So we got good news and we got bad news. Which would you like first? There's good news and bad news. What would you like first? Bad news. All right. So the bad news is not bad news for Yeah, not bad news for anyone here, but core staff ran the plagiarism detection and Most of the people that cheated were in my section. So Yeah, we're in this section which is Disappointing because I get to have fun meetings with no one that I can see in this class So anyone that attends lectures is good, but someone watching this recording Yeah, disappointing so and It's only lab six So hopefully I do not see you in that context, but I guess for the good news So the good news I'm away at a conference next Wednesday and Friday, and we are ahead of the other sections So they're canceled. Yay. So Next Wednesday, so I'll post it on Corkis next Wednesday and Friday. I will not be here so I will not be doing lectures and To make up for it since our exam is like the second last day I will just do like an online two-hour review session like a week before the final whenever it seems good to make up for that two hours and We'll just do final review close to the final because for some reason your finals like at the very end because You got unlucky. So that sound good All right Sorry Next Wednesday and Friday. Yeah March 20th and 22nd, and I'll make an announcement for that too All right, so yeah, we're ahead of the other section. So we get some more practice today So we're doing recursion on string. So third time I say this now. So this is fairly important So a recursive function function that calls itself two things We need a base case so a simple solution We know and a recursive step to reduce the problem to a smaller version of itself Specifically with strings. There's like three General major ways to think about recursive solution with strings So the smaller problem could just be like a character followed by a smaller string whatever is remaining maybe a smaller string then followed by a single character and Then you just do that. So that's working from the end instead of the beginning or maybe it is two Characters in closing a smaller screen. So a start like one at the front one at the back And then you make the string smaller look at those two make the string smaller so on and so forth We can do some more practice. So can we recursively check if a string is a palindrome? Which means a palindrome is just a string. That's the same forwards forwards, yeah forwards as it is backwards like race car like mom like dad like I'm out. Wow. Wow. Wow is a good one Yeah, I don't know really any other ones so Let's go ahead and try to come up with a solution for it. So here I Just wrote a little main function that again does the second version which takes arguments from the command line or from typing in their terminal So again check that there is two arguments first It's going to be the program name and then the second I assume is just going to be the string We're going to check whether or not is a palindrome. So if I just do is palindrome and I do race car So this should tell me if this function returns true It should say indicate that it is a palindrome if it's false It should say it is not and since we have not implemented anything It says race car is not a palindrome, which is not true because currently this is my Implementation for the is palindrome function So any ideas of how I would write this function recursively So again think of what our base case or base cases are and then a recursive solution to said problem Yep Yeah, so yeah, so may maybe base case e is So let's say we need the length of a string so Oops Yeah, well, so maybe so our base case maybe if the length is one We just return true and then Yeah, so We could return s zero Yeah, so we get a bit problem here once we do a recursive step because we want to like chop off The first and the last right so the way I have it written right now is I could do that But that just chops off the first right So, yeah, and we kind of need to check if the first and the last are also equal So looks base casey, but we need a bit more help here. So we kind of want to You know enclose it from both sides Yeah, so yeah Oh So when like we make a string so small that it's just one character or zero So like let's let's think so if we have the example race car so Maybe well our recursive step could be like we just check the the first and the last character and Then if they're not equal, we know for sure. It's not a palindrome, right? But oh, yeah For zero you so if it's but I would argue so the comment is if it's two or greater. I should Or if it's exactly two, I should check both characters That's part of my base case Yeah, so like the case of length two should kind of cover the recursive case, right? Okay So yeah, so in this case, maybe if we think about this, you know are like the first and last character the same So it might be a palindrome. So we just have to check the inner string. So we might check, you know was this ace AC so Is that right? Yeah, and then we would check Oh CA then we check these characters. Okay, they're the same so we keep on trying and then maybe we check Oops, and then we would have the string what Keek kick almost Keck needs K's So then okay see and see are the same So then we just have a single character and then that feels base KC like just a single thing is a palindrome by definition or Maybe there's no characters left like our indexes are the same. So with this It kind of looks like the information we need is like we need one what indexes to compare for the characters, right? So this one would be like we're comparing zero and whatever the like the string length minus one So that might lend us to think that we probably need a helper function. We need more arguments than just a string, right? Yeah, so not quite we do need a helper function You're right that we could have two strings, but we still have to make another function. Maybe yeah So in the helper function first thing usually we just think about what like arguments we need so we need the string Yeah, so we could do what you said like we could make another string or another pointer that points the last and move them or I could use indexes directly Indexes might make more sense to me so I could be do like the first index and then the last index something like that so now Okay What our base case was before is like if the two at the first and last characters did not equal each other, right? We know for sure. It's not a palindrome. So that could be one of our base cases so if The first character Does not equal oops The last character then for sure it is not a palindrome. We can stop we don't have to worry about anything, right? So what would our other base case be like when we essentially get down to a single character? Yeah, yeah, yeah, yeah, yeah Yeah, so our two cases we're kind of worried about is the first should always be the lower index then the Then the last right so at least we need to make sure that if first is greater than last Then well, there's really nothing to compare it like we overshot it So that means it is a palindrome We also have to consider the case where first is equal to last which means the string is of length one, right? So all we would say is greater than or equal to last and that covers both So that looks like kind of our two base cases, right? We either compare the characters and they are not a palindrome for sure or Hopefully we have checked everything else and we are down to either a single character or a crossover Which means essentially we're down to no characters. So those looks like a good base cases to me And again Since there's return statement, it could be Elsa if it could be if doesn't really matter and then let's have our recursive step Could be in an else could not be it doesn't matter So what would our recursive step be whoops base so return so we need to name this something better so Okay Helper all right, it's harder to type standing than it is sitting for some reason so I have to call my helper function then give it s and Then what else should I give it? Yeah, first plus one Last minus one, so I'm moving one character forward each time and one character backwards So I'm just squishing it by one each time right so that Looks good to me anyone have a arguments with that All right looks pretty decent to me So that is my helper function, but we were tasked with writing this is palindrome which doesn't take anything So what should I write for my is palindrome function that just takes a C string? You know just do a call to helper Yeah, so my first should be zero Yeah, so the second one should be string length minus one because their index is right We want to go to the last character if we index like string length directly like The byte at index string length that should be a null byte So it would be valid would be a null byte, but we don't want to check the null byte verse anything So because it's zero index it should be string length minus one So let's hope we go So it says race car is a palindrome so Maybe we just wrote it bad. So let's see race car. Oh Not a palindrome sweet Single let's do single letter a is a palindrome. That's good AA is a palindrome. What about what about this empty nothing? It's a palindrome Makes sense Scream is a palindrome seems to work. Yeah Yeah, on an exam if you're given a task, you're totally allowed to make helper functions in the interest of time I would just you know for an exam. I would probably do this And just name it helper because unless you have to write the better But yeah, it should be the same thing So I would just write that on an exam And yeah, so there's a question why was this reading it as blank? So just has to do with how your shell works Like whatever you're typing into works. I shouldn't say the word shell because you don't know what that is Basically, whatever I type to run this if I just give it empty quotes It's kind of like C ish rules where that kind of just represents a string a string that has nothing in it Because if I just did quotes, I did hi. Whoops. I didn't build it. Oh, yeah, I didn't build it Okay. Oh, right because I didn't call the helper. All right. I'll just rename it So if I do double quotes and hi, it just takes a string hide the double quotes don't go in Kind of like if I wanted to put double quotes literally in a string in C I would have to like escape them the same way So funnily enough it should say that's a palindrome because double quotes equal double quotes So that would also work, but that's just rules for like How this runs it kind of derives the same rules as C All right, any other questions with that? Cool, so we can get some fun stuff too so here's that so I will prefit or I'll preempt this by saying The following I'm about to show you is more features in C that you shouldn't use for this course However, you might have to read them or use them in a future Although some of them are bad ideas. So one ternary conditional operator It's ugly Some people use it. So if you ever see a question mark in C, it's valid So it's another expression and the syntax is a conditional so something that will evaluate either to true or false and then a question mark and then while the value to Evaluate this expression to if that condition is true and then Colon and then a value if it is false so you can use it in the lab if you really want because we don't really read your code, but like this stuff unless it's very simple I suggest not doing this because This might save you like declaring a variable and then an if and an else So if I declared a variable and then did like if conditional set it to true Set or set to this value if it was true else set to this value It'd be the same thing. This is just done in one line So some examples are well, this one's really really small But if you did true question mark one colon zero true is true So the value of this expression will just be one if I do false question mark zero Colon zero well, it's false. So the result of this whole expression is going to be zero So you can choose to use it use it for really simple things because if you do Some gigantic piece of thing and then a question mark at the end It might just look like you're questioning your own sanity or something like that And then like if the value is really complicated It it like quickly becomes really annoying to read Especially if you like read your code later and like you even forget question marks exist It's like the only time you use question marks. So you might want to avoid it, but for little things Where it is very obvious you may use it, but Generally discouraged because it's just something else you have to remember It doesn't really give you any features aside from just making things a bit shorter and more compact Which you know, I mean that's the whole principle behind like mathematical notation. No one can read it But you can write it really fast. Yeah And I exam it would save you time. Am I allowed to put it on? That's a good question We will have to see because you are the only section that has seen this Yeah, I would play it safe and not especially Yes, some of the grading kind of gets sketchy as it is already so probably best to avoid this All right, other fun thing you can do is You can give your own meaning to numbers and use that meaning with something called an enum short for enumeration It's basically defining your own type So the syntax for it is is like typically represents some type of category or something like that so you could say a num and then give it a name and then you could essentially just give a name to some value and then actually Tell see Like the actual integer value you want that name to represent because you know ASCII at the end of the day it just is a mapping to a character to a number and Defined by the ASCII standard and you can go ahead. You can define your own magic numbers if you want So if you want to define your own enum, it's a new type So you can just use that variable as a type It should be just below the includes and not within a function. So for example We could eat so yeah a question is it by any chance similar to a class an object in Java It's our own type, but it's our own. It's essentially our own integer type So it just converts directly to a number We will get into if you've heard of the word class or anything like that we'll get into that in the next lecture and All sections will have that only we talk about in arms because you know, you'll probably see it in C So how is it used? So you might create an enum? like Typically for a month Maybe I don't want to remember the month number like I don't know for the longest time I couldn't figure out what month number may was and I'd have to like Google it every time So if you're a dumb like me, you might just rather have Names you can refer instead of the numbers so I could create an enum called month and then just Give each name so each month name its own number that corresponds to its actual month number So like January could be one February could be two March could be three So on and so forth I Could do this without an enum. It just helps you read your code a bit better So like for example, it's basically an int and how I would use it is instead of declaring the type as Int month I could just you enum Month and then that is the type and I could also just call my variable month if I want to not be creative And why would I do that? Well, because if I write a function like this it Reads a bit better. You can actually kind of understand what the hell I'm talking about. So if I write a function that Set is is winter semester where you give it a month that tells you whether or not this month is actually in the winter semester Well Without this I'd have to write like return if the month is equal to one or two or three or four Maybe it's easier to read if you just say hey, it's the month January February March or April and then someone reading this might be like Oh, okay. Well, that's obviously right. I don't have to look up anything else seems to be good And how you would use it in your program if you use it as like a scan F It's just an integer. So I could just say enter a month month one through 12 do a scan F with a Percent D Specifier because it's an integer and then my function would go ahead and work as I expect so here's what that would look like and maybe I Do month enter a month? Let's say whatever the month three was that's this month right March. Yep. All right. I'm great And it says yeah, probably in the winter semester So just makes it a bit easy to read and Yeah, and e nums are only for ints In other languages or like in the next C C++ you can use it for doubles and stuff like that, but in C. It's basically just an integer. They keep it simple. Yep so Enum month is like the type Like saying this it matches that so it's basically the exact same as just saying int So this basically saying it's an int called month But instead of it I have to write enum month and I just called my enum month month because I'm not creative But like I could change this to any name I want as long as I update everything else like I could change this to M But then I just have to update my variables and That's no problem. But if I change this enum month to Any name it's gonna say I don't know what the hell that is because it has to match That type up there. So you might see this in code You might not Basically, it's just you can create your own magical numbers because well all computers are our magical numbers and Guess what? LLMs like the big large language models. Well They just assign Parts of words to numbers and then generate random more numbers. Yay. Everything's a number Okay, yeah, I answered that we're in C. It is basically just an integer. So whoops so I Could also do like an em that represents maybe a direction or something like that. So like maybe I say North is one and then here I don't specify numbers for anything else So C has some very simple rules where it will assign numbers for you So it will just assign them to you sequentially. So if I just say one and say nothing else Well, then that means east is going to be two. It's basically going to just take that number and increment it every single time So in this case east would be two south would be three and west would be four So it just assigns numbers in the order that you write them in after that enum And if I didn't say north is equal to one the default is the first thing is just equal to zero So if I didn't write anything north would be zero east would be one south would be two west would be three So but as I wrote that for some reason maybe I want north to start at one So I could just write one let it fill it in and again it will get it will assign the numbers like this So why would I want to do such a thing? So I might want to do such a thing Because maybe I write like a print direction function and Maybe I use it like this so typically this is also what they're used for to like kind of Identify something maybe you want to print the direction So maybe I write print direction that takes you numb direction and then I check well if the direction is north I'll just print the string north. It's east. I'll print east if it's south. I'll print south if it's west I'll print west and then you know in your program. You can just say print Direction, maybe I want print. I don't know whatever west is So take my magical west value, which in this case is just the value for Run it and then whenever I run this it should Yeah, it should just print west whoops so Typically use it like that. This probably looks like a bit like One of your labs where you just had directions. You just had more directions. So typically it kind of looks like this So any questions about that? Yeah Yeah, so other ways I could make this shorter is I could have If I wanted to I could have an array of Strings and I could index them by the num number and just look it up. So that is something I could do We'll see something that's equivalent that pretty much gets the same thing across So any questions about this? Perfectly valid way to write but yours would probably go faster So here I'm printing There's like a lot of repetition here, right? It's like if D is equal to north do something if D is equal to east do something if D is equal to south do something Kind of gets like a pain in the ass. So instead of many ifs, there's another construct called a switch And you might have seen this before too. It just saves you a bit It has some weirder rules, which I guess is why it's discouraged But we can go into it. So the syntax of a switch statement is Switch and then a variable name and the rule for it is it will just check whatever the value of the variable is and Then essentially the execution of your program will just jump to Some what like one of these case statements that matches that value So see just skips directly to there and starts running whatever code comes after it So like case and then some value. That's not something it can run That's just where the code will go to then it will start executing it until either it reaches a break statement Which we saw in loops so it behaves a bit differently in switch statements If it encounters a break statement anywhere within a switch statement It just goes directly to the end like the monopoly go to jail So you just go directly to jail. Don't ask was it don't collect $200 something something Do not pass go do not collect $200. All right so Yeah, so that's how it works otherwise it just execute statements until it makes it to the end of the switch statement and To like with if statements we could have an else if it doesn't match anything so the equivalent for a switch statement you can have a case called default and If there are no matches anywhere else it will jump to that default label Otherwise it just skips directly to the end So I could rewrite my code a bit differently if I don't just don't want to check the value of D over and over again In this case, it doesn't really save me any lines it but it saves me from writing D over and over and over again so Possibly a bad example, but kind of illustrates the point So here I could switch on D and then if it's north then we would start executing the next statement after this So it would print f north and then break which would go to the end and not execute anything else in the case that we saw It would jump here to west Then print it west break go the end Otherwise if it didn't match anything it would just exit the program with a failure. So typically This is what you do for enums. You'll like put some error handling code in the default because I Know in this case. I'm probably not going to come up with a new direction other than north south West and east wow, I forgot my directions because that's great But maybe you come along and you're like hey Maybe I'll just consider up a direction up and down and then if you do this then suddenly up and down would Not be covered. So maybe you have the default case where you get some error code instead of just not doing anything So other so any questions about that probably wouldn't save you time. Yeah Yeah, so this is slightly faster than if statements for most compilers because it will do what you suggested and Essentially this Internally builds an array and it'll just go directly to the array instead of checking. Oh Is this okay else if is this? Oh Is that that right? So this like I can't do anything complicated. I'll just check the value of this and then jump to one of these So it can't do anything complicated. Just checks a single value but it's a bit easier for that and yeah, this will actually Generally run faster because it'll implement as essentially an array All right. Any other questions about this? All right, so Oh Yeah, another question if there's no indentations would see know where the case block ends or doesn't know based where the next case is so in this case what a pun so Weird things that will happen. So the indentation here doesn't matter at all. So if I even move this oops so What is my computer doing? All right? So if I move this like indentation while no indentation C cares about at all So if I do something like this doesn't matter usually with case statements You indent the case at the same level as switch That's just generally how people do it But you could do it like this if you want want not gonna affect anything C doesn't actually really care So if I run this let's just make sure that this does the exact same thing So let's print Direction let's print south So now if I print south. Oh print west Oh wait, that was the wrong wrong program. Sorry. So yeah print south so Fun things we could do here Maybe I Here let's have some fun. So maybe after myself. Maybe I forgot this break common mistake Any guesses what will happen if I just forgot to put that break in So does it so you think it'll just continue going so it will So it'll do this and then exit so the west one So south then west and then it's done. So so yeah, there's a calm comment There's no way it's going to step into west so we will not see West printed at all, right? Southwest so The rule here is it executes as Normal like we see can't execute these case statements. So they essentially get ignored So what happens is in this case I have print direction south So it would find like we switched on D. It's currently south So execution would jump here in the switch statement. Well, this isn't something it can execute But would execute print f print out south and then the next line It just goes line by line like normal. It wouldn't execute this line because what just says case west Well, that's where I would go if it was a west. I don't really care because I'm executing So it wouldn't execute that that would execute print west and then it would print or execute break And then go to the end. Yeah. Yeah cases only come into effect whenever You like it's just where to start in the switch Yeah, yeah, if you have encountered labels, hopefully you haven't before but it's basically a label can't execute It can't do ever just tells you where to go. So that is a common very common Kind of drawback with that says if you kind of write it like that where each thing should do its own independent thing If you forget to break well, then you have this weird thing where it just kind of skips into the other one And you might not expect that you might get like south-west and If you really screw it up like the labels can be right next to each other So even if you do something like this Well, if it's south It's going to match here here. Let's just say we forgot both lines so if the value is south it's still going to jump here then well The next thing it's going to execute is not that not going to execute Then it would just print west and then break and then be done So if we compile this and we just forgot everything and just print west What would happen if I just forgot the case completely So yeah, so if I forgot the case completely Probably won't see anything but we see this minus this one thing which essentially means it hit this exit so because South doesn't match any of these it would match default and then just exit Run that and my program is done now. It doesn't really matter. What else is there? so All right, other questions about that Fun looks kind of ugly though if you'd like having enum direction D kind of or When I had enum month month kind of looks ugly So let's solve that ugliness problem So you can rename types with another new keyword called a type def So the syntax of a type def is you just take an existing type and then you give it a new name so you just Replace new name by whatever you want to call your new type and then the type by whatever You would like to use in place of this name So why would you want to do that? Well, for example, I could write something like type def int To number t number underscore t So then afterwards I can declare variables with the type number underscore t and then if later I decided well, I don't like integers anymore every number. I want in my program now I want to be a double well I can just change the type def to be type def double number t and then suddenly my integers are now replaced by doubles and I only have to change one thing and note here usually We append like a underscore t to indicate that it's a type So let's see how clever we are so here. I have my type def number oops So here I have my type def number So whenever I use a number t it will replace that by an int whenever we compile it But here let's create a number t called a one called B Sign like initialize it to one or sorry two and three and then add them together so If I go ahead and run this Right, I print it as a Int if I run this what am I going to see? five hopefully right A plus B is five. All right. Yeah, we're not crazy, right? So why this might so Generally using a type def with it's is a very bad idea Because what happens if I actually do what I suggested before which I do not suggest do not do this What would happen if I just did this? Will it give me a warning? Let's So yeah, it's already given me some hint that says format specifies int, but their argument is type double So sure I changed my numbers like if I just wrote double a and double or double a and double B Sure, it would just get like two point zero and three point zero But whatever it doesn't change your format specifiers So you're probably going to be screwed because you probably use that somewhere so now you have a mismatch where this is now you change it to a double and your format specifiers for an integer and Generally when you lie to see functions very poor things happen So we get negative a lot So we lied oops. We made our mistake. So not really going to save you any time I should have just switched them back to a double anyways because oops Because to fix it off to go through it anyways and change a whole bunch of things So I'd have to change that to LF and then yeah, it works how you would think but you know You might go ahead and forget something All right, so why did I show you type def if it is such a poor idea? Well the typical use of it you have to get into some weird C language rules Which I looked ahead and is encouraged some people like doing this some people don't so What you can do is you can use that type def to save you from writing a num all the time with types so You can actually create a enum without a name That is a perfectly valid thing to do if I did it without a type def It would be useless because I'd never be able to create a variable of that type because it doesn't have a name But what this does is it says type def So just take this existing Nameless enum that has a northeast south and west and I will rename it direction underscore t So then afterwards if I want to create a variable with it instead of enum direction direction You might argue that this is a bit nicer to read where it's just Direction underscore t so the type of a direction and then I call it a direction that I could do equal north Something you can do cool, right? maybe so So final exercise going back to string recursion So could we implement? Stir car recursively so that is where it searches for a character in a string and returns you a pointer to the match Or null if there is in no match So I can leave that to you. Yeah, so Quickly this looks like The case of recursion where I should probably just think about the first character And then the rest of the string in this case if the first character matches the string I'm looking for I should just return a pointer to the string Otherwise if I make it to the end and make it to the null byte I should just return null to say I don't have any match. So Our solution Should probably I'll just put this up real quick probably looks something like this. So I can cheat a little bit so instead of indexing What zero or element zero the same that I could do the same thing by just Dereferencing the string since it points to the first character anyways So my base cases would be if the current character. I'm pointing at is the null byte return null There's no match otherwise if the First character equals a character. I'm looking for return the current string Otherwise in my recursive case. Well, I could just move the pointer one character over and Still search for that same character right nice and simple nice and compact and I can go ahead. I can run it and It does the same thing for both programs. So seems to work. I could search for I don't know in a Whoops So if I search for an a it's not found so they should both return all the a they both return all they seem to work so Questions about that. I went through it fast, but Same so for extra practice if you want you can do Stirred car, but it returns the last care the last match first instead of the first Could do that It's a little bit trickier, but not too much. So Any other questions we can wrap up slightly early? All right, cool a bunch of new see features that aside from type def We will not use but you might read it or you might find it useful. You can write whatever you want in your programs But probably don't use it for the exams. Do not confuse the ta's their job is hard enough already So just remember pulling for you. We're all in this together