 Welcome back to 105. So this is last lecture until our two-day break. So again, don't come to class on Wednesday and Friday. Do come to class next Monday. So let's get into this because we will need this when we start talking about Lab 9 stuff and it might be useful. So structures. What are structures? So in C, we can group together variables with in something called a structure. It is a new type and, of course, it's C. So they couldn't have just called it structure. They called it struct. So they made it shorter because everything they had to make shorter. So the syntax to define a struct is, well, you just type the word struct, then give it a name, so name representing what you want to call this group of variables. And then inside of the curly brackets, you can put as many variable declarations as you want. So as many variables as you would like to define, you give them a name. So similar to an enum, short for an enumeration, well, you define a struct just below the includes and typically you do not do it within a function. So we'll spend the rest of the lecture talking about why we would use this, why it makes our life easier, and some motivation behind actually using it. And if you've seen like Python or C++ or Java or anything like this, this will be familiar to you. Essentially, they just took the idea of a struct and made it a bit easier to use, but at the end of the day, it is the exact same thing. So let's start off with a simple task. So we're just going to calculate the distance between two points. So I could write that as a function. So if I have two points, a point is an x and a y. So if I want to calculate the distance between two points, well, I could represent them as x1 and then y1 for the coordinates for the first point, and then maybe x2 and then y2 for the coordinates of the second point. And then if I want to calculate the distance between those two points, it's just the difference between the 2x coordinates to the power of 2. So I could write pow, the difference, and then 2.0. So that will just square it. And then plus the difference between the y coordinates, so y2 minus y1 to the power of 2. So again, we get some review using our math function. Pow is just taking this as the base to the power of whatever the second argument is. And then in order to calculate the distance, I just take the square root of all that. So I just give it to the square root function, which, of course, they called squirt short for square root because, of course, they did. And then if I wanted to use this, well, I could, in my main, I could define points x1 equal to 1, y1 equals to 2, x2 equals to 4, y2 equals to 6. And then I could calculate the distance, and then we can review. We can go ahead and just print it to one decimal place because it is a double value. So if I go ahead and run this, they get 5.0. That's the distance between them. This should be nothing new, right? Any questions about this program as written? Fairly straightforward. We're just going to make it much, much better today. So we're good. We're good. All right. So we could have written this at, like, what? Week or lecture, like, six? Something like that? So for a function like that, for distance, not too bad to remember which variable is which. I have an x1. I have a y1. I have an x2. I have a y2. Not too bad to keep track of them. But what about if I write a function that just, like, prints a point? So I just write a function just called print. I give it an x and a y, and then it will just print off the coordinates just rounded to the nearest tenth. And while this is a bit awkward to use and might lead to errors, so just naming variables x1, y1, y2, kind of a pain, if I accidentally write something like print x1, y2, that's one coordinate from one point and one coordinate from another point. So that probably doesn't make sense. It's really easy to do here. Might not be one of the two points we intended. And debugging it might be confusing because you just don't expect that. So since we learned what a structure is, we can just make a structure that represents a point. So we know a point is like a logical thing. So a point is a coordinate. So I could just create a structure called point. And then inside of it, I'm allowed to make as many variable declarations as I wish. So a point, I'll just say, consists of an x and a y. Again, they're going to be just doubles. So this will create a new type called struct point. And then you can just use that as if it was an int, a double, a char, a bool, whatever. So you can create a variable with it. But instead of just saying its type is one of the things we've already learned, you could create a new variable by saying struct point. And then I could say p1. So I could create a point called p1. And the type of it would be the struct point that has an x and a y. So to access the inner variables or to access the variables within that structure, usually called fields or members by the compiler. So you might see some compiler messages where it calls them members. You can access them by just typing or after the name, just putting a dot. So for example, if I want to access x of p1, it's just p1.x. If I want to access y, it's p1.y. So questions about that, we just get to group them a little better. And then we can go ahead and rewrite our function. So first, I'll get into a common trick. You will see that it's arguable whether or not it is clear or not. But we saw, like, type def before when we had enums. So the syntax of a type def, just in case we missed that one on Friday, is you can type like type def is a keyword. So you can do type def. And then a already existing type. And then you can rename it to a new type. And then you can use it as either of the names. So in this, if I just do type def, I don't know, type def int num underscore t, then whenever I actually use a type num underscore t, then it would actually just replace it by an int. And then I can go, I can change this type def whenever I want, just creates a new name for a type. So I can use this with a struct to make it arguably more readable. So we can create a struct without a name. So I could do something like type def struct, and then not give it a name. Do the curly brackets. Give it a x, which is a double, and a y, which is a double. And then I name that unnamed struct point underscore t. So that is going to be my name for a type that's supposed to represent a point. So afterwards, I can create a variable with just point underscore t p1. And then I can access it like I could before. I could do p1.x, p1.y, so on and so forth. But usually, unlike enums, you should still give structs a name. So if I want to do this, I could do type def struct point, and then give it the curly brackets, give it the x and the y, and then give it the new name point underscore t. And now I have two names I can make it. And I can use whatever one I want. I could use struct point. If I don't want type struct, I can use point underscore t. But both mean the same thing. Just have an x and a y. So if I wanted to create our two points and initialize the fields, I could do something like this instead, which seems like I kind of logically grouped them here, but seems like a lot of work here. So I could create a point underscore t called p1, and then do p1.x equals 1, p1.y equals 2. Create another point. I'll call it p2 because I have original ideas. And then call it p2.x, or sorry, set p2.x equals to 4, p2.y equals to 6. And then that looks, that does essentially what I had before. But turns out, with structures, we can initialize them like arrays. So instead of doing all of that, I can just kind of borrow the same syntax as I have with arrays. So instead to initialize it, I could write point underscore t, p1 equals, and then curly brackets. And instead of just setting array values, I'm setting fields in the struct in order. So since my struct had x and then a y, well, this first one would set x, and the second number would set y. So this is the same as just setting p1.x equals to 1, p1.y equals to 2. But I can just do it whenever I declare the variable. I can initialize them straight up. So I could also do p2 equals to 4, 6, and that will be the values just in the order you declare them in the struct. If you want to set the values in some different order, there's a funnier looking syntax. So I can give it a curly bracket, and then I can say which field I want to set to what value. So if, I don't know, for some reason, I wanted to set y first, but y was the second thing defined in my struct. Well, then I could just do dot y equals whatever. So I could dot y equals 2, dot x equals 1. And yeah, there's a question, how the computer stores these values. So it basically stores these values like an array, except that all the elements can have different types. So it does some magic to figure out where they should actually be in memory. So like arrays, they often be of the same type. For structures, they don't have to be the same type. I could put bool, whatever. But they're stored more or less like arrays, and c gets to keep track of where they actually are in memory. But they'll be in one big chunk of memory altogether. All right, so now I can go back and I could rewrite this code. So I could be like, oh, OK, well, I should probably use, so create a struct, so I could do type def struct point, give it a double x, give it a double y, and then call it point underscore t. So now I have my struct point, and I want to rewrite these functions in terms of points. So maybe for this function, what I would do is, well, it takes two points. So I could say point t, p1, just assume that they're like integers or something like that. And then I could do point p2. And then inside of here, instead of just accessing x1, x2, well, they're from two distinct points. So instead of x2, that would be p2.x. And instead of x1, that would be p1.x. And then for the second one, y2 gets replaced by p2.y, y1 gets replaced by p1.y. And that should be it. My print function would be similar. Maybe I want to replace it with point. And then here I would just do point.x, point.y. And then whenever I calculate my distance, so I could create p1, initialize it. So an x and then a y, create a p2 for saving some lines of code. And I'm also grouping things that are logically together. All right, there we go. So doesn't that look a little better? It makes it clear that I'm calculating the distance between two points. And then I could also print out a point if I want. There's no printing one coordinate from one point, one coordinate from another point. They're logically grouped together in this struct, which for this, basically it's like an array. So if I go ahead and run that, boom, should get 5.0. Same thing, but helps me group concepts together. So any questions about these changes here? Yeah, so do I have to write this above all the functions? Yeah, so this I would have to write above all the functions because the C compiler is dumb. It just reads it from top to bottom. And if I use point under score t without telling C what it is, it gets really confused. So we can see what that error actually is. So let's just move it down before this function. So the print function knows what point t is. But we'll see here, we already have some angry, angry C compiler. So if we do this, it will probably just say that unknown type name point under score t has to come before everything. But yeah, good to see errors because that is a common one. All right, any other questions? All right, so how could this possibly get better, right? So here's what we had. So it worked. However, no one really writes this because remember, how does C deal with function arguments? So do functions get complete copies of things? Is C copied by value? Well, yes, it is. And unlike with arrays that just kind of get turned into pointers, well, the same confusingly doesn't happen for structures. They get copied. So function arguments in C, again, so this is also review. They are copied by value. And sometimes structures can be very large. And it gets a complete copy of them. So even if it is, your structure has like 1,000 variables in it. And it is, I don't know, 8,000 bytes large. Well, each time we use a function there, they get copied by value. They get a new copy of the struct. And of course, since they're copied by value, if we wrote function that would modify the x and the y, well, if we modified it in a function, we would modify that copy of the struct and not whoever called the function. So we wouldn't get our modifications. And also it would be really slow. So in general, it's generally frowned upon to do structs just straight up by copying them by value. And for speed reasons, for usability reasons, and normally programmers just always use structures as pointers. So if I want to write my distance function, I would write just a pointer to P1. And then a pointer to P2. So let's see what happens when I do that. So I change these to pointers. And then in my main function, well, I can't just like if I was using scanf or something like that. I would have to give it the address of it, not the actual value, because I don't want to copy the entire structure. So I'd give it the address of P1 and the address of P2. But now when I compile, it does a bunch of things. In fact, I get an error where it says P1 is a pointer. So now how would I actually access the value of P1.x now that P1 is a pointer? So think about what I would have to dereference to get that struct back from the pointer. Yeah. Asterix? Yeah, the dereference. So instead of writing P2.x, what would I have to write? Yeah. Yeah, so I might have to write star P2.x. But that doesn't quite work, right? Because what it's trying to do here, based off the precedence rules that you don't really have to remember, what this would do is try to take the field of this first, so try to access P2.x, and then dereference that. So I have to tell the C compiler what I actually mean, so I could just put in parentheses. Yep. Oh, yeah. Whoops, I said it. Same thing. Yeah, we don't know that yet. Yeah, so if I wanted to do this without anything special, I would have to put parentheses around it. So I could do dereference P2, and then .x. And because of the preference rules, I always have to do parentheses. So does this look nice to do, and is this fun to do? So are we having fun right now if I change them all to something like that, or does that look like really ugly? Looks pretty damn ugly, right? And it's not even working yet. I'd have to change this one. So we do this, and the parentheses are not optional. I would have to have them. So let's see. Make sure we compile, and it works. So now it works. But doing that, that looks like one of the ugliest things I have seen since, I don't know, I woke up this morning and saw myself in the mirror. Boom. Boom roasted, all right. So there is actually a special C operator to access fields through a pointer. So if I have a pointer to that structure, well, to access it, I would have to dereference P1, put it in brackets because I need to make sure the preference rules, like I dereference it first. So I have to do this. It's kind of a pain. There's actually a new operator that just looks like an arrow. So it is the minus sign, and then a less than. It doesn't mean subtract anything, or wait, that's greater than. It doesn't mean subtract anything, make it greater than. It's supposed to look like an arrow. So it's supposed to look like it's pointing to something. So that combines dereferencing and field accesses in just one step. So instead of doing parentheses, dereference P1 and parentheses dot x, kind of a pain, I could just do P1 arrow x. So I can change it, I can make it a lot more readable, and this is what most people do. So I can just get rid of this. Instead, I could just do P2 because it's a pointer, P2 dot x, or arrow x. And this one could be P1 arrow x, and then P1 there. All right, so I could do that. That looks a lot better, right? Okay, well, if they have to be pointers, it looks a lot better. So if you try to do something like P2 dot x, you're compiled.