Mmmm, pun headlines. Not sorry.
So, looking at structs. The write-up for Ex 16 starts with ‘OK, do the write-up’. So, what does the #includes stuff get?
#include <stdio.h> I know about. It lets you put things in and out, so printf lives there.
#include <assert.h> apparently crashes my browser when I search for it. Which is apposite.
Apparently ‘assert’ makes the case that something exists, and then if it doesn’t, throws up a warning to stderr. I guess stderr is also controlled by stdio, as it’s a line to print to. 2/dev/null is my favourite way of stopping the screaming. So in this case it’s checking that who is not NULL. We’re not just picking up a non-entity and trying to work with it, and if who != NULL then I guess that’s the check we’ve just succeeded at what we’ve done.
#include <stdlib.h> gives us malloc() – memory allocation. We’re grabbing a chunk of memory to use for each copy of the struct. So, for obvious reasons, it also gives us free(). Once we’ve allocated, we need to be able to free that up, or our little ghost people will wander in electronic halls forever and there will be a bad Tron sequel.
#include <string.h> must let us play with strings. We have strdup() to handle our name. It also gives us NULL, which is cool, as stlib.h also seems to give that to us. It’s probably very popular at parties.
struct Person defines what a struct called person is. It’s got some attributes inside. So, when we get to struct Person *Person_create we’ve got something to look to and check. It’s sort of like defining an int and then putting a number into it. We define a Thing and then we put how to create the thing as a subsidiary part of that.
struct Person *pointer-to-whatever-our-name-is instantiates a struct and the bits underneath fill it. Note it’s in the middle of our Person_create function. So we grab the attention of the computer, shout at it until it creates a struct with a pointer of the name ‘who’ like Joe or Mat or Cthulhu, and then we go forward from there and allocate memory from that point. For extra points, we choose a bit of memory that isn’t going to write over anything else because you put Cthulhu in the wrong place. (Cthulhu in the wrong place will /severely/ mess up your day.)
The =malloc(sizeof()) part makes sure we’ve allocated memory to the maximum size a Person can be. That’s pretty large in the case of some sedentary sorts.
I think assert(who !=NULL) checks that that happened right, but it might also be that ‘who’ is not a name of 0 characters. Those might look the same in the wrong light. It’s checking who, rather than checking the pointer named who. Someone call for the fucking Tardis.
who->name=stdrup(name) is the stand-out here, so let’s do the next line first.
who->age=age is pretty obvious. Within the struct sub-language, you’ve got -> which says ‘put this into the struct’. So assign ‘name’ from the input of the function into the bit of ‘who’ that is labelled ‘age’.
The same applies with who->name=stdrup(name) except we handle it a bit differently because it’s a string, not an integer. It’s string duplicate. It copies the string we want, the name, into the space we have reserved for the name. I don’t know why that’s explicitly different from int – maybe it’s for security, maybe it’s because it’s easiest to copy a string that way, I just dunno. But that’s what it does.
The return returns the whole object. Later, we’ll see that we run this function with a = in front of it. We’re making ‘who’ and then assigning it to a named pointer we create at the same time.
Person_destroy is my favourite… no, let me alter that. /Running/ Person_destroy is my favourite part of the program. I could sit there running it all day. Only I can’t, because the person has to exist to be destroyed. Again, if there’s a NULL entry, we can’t destroy it, and we output that. I can see a bit more sense in this than in checking the creation. You don’t want to typo the name of a poor unfortunate to be blatted to oblivion, and let them live, after all. But I’m also pretty sure both will be good practice, and if I’m going to have my fun at the end of a function’s life, I can build in sense at the start of it.
We free up the name separately from the rest. I guess because the name is a string, and has to be treated differently, so you only free up to the null byte at the end. Maybe you can group different strings to destr… uh, ‘free’ in the same way as we group everything else on the next line, but we’re doing the strings and then everything else as a one-er.
(Person_destroy($^). Mmmm. It’d be so peaceful.)
Person_print doesn’t check on the existence of the person in question, but I have people for that. It prints out everything we explicitly list, according to the -> syntax. This is likely a bit easier to remember than ***pointer-to_otherPointer(pointer002).
Then we hit main(). It’ll return an int. That int will be 0, because nothing will go wrong. Nothing, you hear me?
Now, we have that equals sign I was talking about up the page. We make a person we label ‘joe’ for the computer. We give him a memory address and fill in all the details, and then we link those details to pointer ‘joe’. He’s 32. His life will be short, although it will have some miraculous aging.
Ditto Frank. Name ‘Frank Blank’, pointer-name, ‘frank’.
%p is the only new-ish part of printf. It gives us the address at which the pointer-thing resides. *joe points to %p where %p is labelled ‘joe’. To find ‘joe’ we look up *joe and that gives us the address %p. Then we run the function that prints out their details, Person_print.
We do the same for Frank. Frank moved away from the neighbourhood and changed his name, but he’s still in his brother Joe’s shadow.
Ahem, yeah, we just call that function we discussed earlier. Joe’s brief, warm moment of existence is over, and we get back the memory. If we’ve had a /really/ bad moment and killed the wrong person and we know the memory address we might be able to copy him or install a new Joe very percisely over him, but frankly that’s advanced ninja work, and I’ll be having none of it.
Our crime is complete. Nobody can prove Frank or Joe ever existed. We return ‘0’ to say that all is well, and end the main function.
I should go back and write this up as comments in the code, but I had too much fun blorting it into a longer form. Don’wanna!
Probably will, though.
Extra credit – can’t work out how to remove memory allocation from stack. I’m not using malloc() so I can’t use free(). Everything else works.