home

Tutorial index

C Tutorial VII: Functions:

Ok, so you made it so far and you possibly have some very big programs which are getting hard to debug, so you are possibly wandering how much harder does it get to make a larger application with even more features. The answer is, I made it rather hard for you when it’s not that hard. Functions will make your life incredibly easier just as you finish this tutorial, which is the last one that covers important aspects of programming. I did not teach you functions earlier because, to start with, I find it is easier to learn the interaction of functions with the other stuff this way, and also because I made you write some nastily long code, which gave you some experience in debugging, possibly revealed some frequent mistakes people make, and showed you why functions are important. Enough explaining my motives, let’s get down to work.

You have already used numerous functions, printf() and scanf() first of all. A function is a set of instructions that you summarize in one name and can use it anytime you want, just by calling that name. The stuff it works on are passed as arguments, and you know how that is done too, just think of the arguments passed to printf() and scanf(). But how do you create one?

To start with, to work with a function, C needs to know it is over there. Declaring a function is done in the same way you declare a variable – more or less. You declare it’s type (int, float, char…), it’s name, and in a parenthesis the arguments it takes, along with their type. The parenthesis is empty but still there if nothing is to be passed, in which case the function type is void. Void can also be used with a pointer if you do not want to define what it points to, but I haven’t run into such a need so far so that’s going into the extra material section. However void is frequently used. So if I were to define a function that gives me the health of a struct soldier, I’t type:

int tellHP(struct soldier theSoldier);

            and after that I’d refer to the particular soldier as “theSoldier” inside the function, regardless of who he really is during execution.
After all this, you have to tell C what this function does. You can either omit the semicolon and open a code block (curly brackets, remember?) or you can retype the same line anywhere else in your file and then do that. The reason for this is that if I have two functions and each one refers to the other, the other has to be declared before the one. Obviously one has to be declared after the other, otherwise something is going really wrong, but if the reference is under both declarations, you are sure that the functions exist.

The part where the code goes is called the function definition, while the declaration itself is, well, the function declaration. This is rather important to remember as in Visual Studio, and probably some other compilers, you can right click on the function and go to each of these separately.

Variable scope:
There is an issue with functions though. What is made in a function stays in a function, so if you try to change that soldier’s HP in the function, nothing will happen. What this means is that the function allocates it’s own memory and works with that, and what you give it is just a value to put in that memory. What is in the original memory is just copied, not used. In general you worry about what scope your variable is in because of a convenience C grants us, you can even name a variable in a function with the same name as one outside a function, C will use the inmost one, the one in the function. Variables declared outside main() are called global variables and are the outmost possible. To be perfectly honest, a function will look for the variable in itself, and if it does not find it it will look in the global scope. The only other possibility is with code blocks. You can have a variable with the same name as another one in a different block or the blocks outside this code block, C will look from within the block outwards looking for the variable. So how can I work on something outside a function anyway, without having it as a global variable? The answer is simple and intuitive. I can give it a value, right? What if the value is the address of what I want to work with, and I work with that? It will work perfectly. To do this, you only need to declare the arguments as pointers. The simple method of passing arguments, that is, passing the value and not the variable itself, is called passing by value. The later method, with the pointers, is called passing an argument by reference.

Return type?
I said something about the type of the function. Remember in main() where you type return 0; ? Notice how main is an int usually. The type of the function is generally the type of variable it returns. When a function is called, it returns a value, if you have used rand then you know that you will type x = rand();, this is a perfect demonstration of this. In this example x stores the value that rand returns, however you can call rand() without storing it’s return value. This is done constantly with printf() – if you want to find out what printf() return either google it or take a look at the extra material section.
So, even though it’s not always used, it is always returned, it’s just stored in a temporary variable and dumped. The return value must however exist, so if you say that your function is of type int, you have to type the return command and then an int variable. This can be omitted with void – after all that’s what the return is, empty, void.
There is another use for the return command though. When the return command is issued, C immediately exits the function that is running and gives the return value to whatever called it. This is useful for exiting a function at any point, often used like the break command.

Passing strange data:
You probably find it all rather straightforward, but I should tell you some things because it is not. This is programming, the real thing, C will do exactly what it says it will do. If you pass an array, you are passing a pointer, an address, all operations are done straight on it, no scope applies here. This is a good reason to pass arrays as pointers, and cast your thoughts backwards, when I said that sizeof() will give you versatility with your own functions.

When passing an array C has to allocate some memory. It can prepare the memory for a single pointer with undefined length (single dimension array), however it will not bother to do so with an undefined number of pointers with undefined lengths. When you pass an array as an array, you can only leave one bracket blank (people who do not go into this stuff think that they can either have as many empty brackets as they want, or note at all, in truth, you can only have one). If you want more dimensions undefined, you will have to pass it as a pointer and figure out how much there is of it inside the function, which is why you want great knowledge of sizeof() and pointers. Note though that this might prove faulty, and you might have to determine the size of each dimension outside the function, and pass it as an argument, there is no guarantee here.

Another question here is the passing of a struct. Well, actually there is no question, C works with bytes over here, so all it does is take the defined number of bytes and copies them, it will not get confused with the multiple member variables, and this is why we can also pass pointers of undefined size, arrays, because it checks the size on the spot and just copies blindly. So treat structs like any other variable type. You will better understand this if you study unions a bit, however I find no need for them so far so I might not cover them in any later tutorials, but you better browse for yourself.

This pretty much is what you need to know about functions, I am certain that you now will make much more organized and efficient programs, easier to debug and much easier to expand. As a matter of fact, you know all the basics to well structured programming, and you will discover that even file I/O (Input/Output) will be a much easier to learn concept than these. Practically, there is nothing you will meet (until you enter C++, C#, anything based on those like the XNA, or any other languges with similar principles like Java) that will not be based on functions, structures and pointers.

So now, using characters as your output and commands as your input, you can do approximately anything doable with these means, you can make chess (ok, this will take a while, and you will have to take a lot of time studying AI), go (the Chinese game, though it also has some AI in it), or anyway maybe battleships, the classic boardgame, but you could even make something like Stratego or Monopoly, which are probably easier to implement. Draw inspiration from boardgames, especially the less-known ones should be easier, but also just think of stuff you might like to do. A big tip: use a 2d array as a grid for terrain, a pointer to select a particular tile, and lots of functions so you have many actions to do.

From here: I would suggest you also read through any more advanced tutorials I have, and try to make something modestly big for practice. If you choose to go with the stable and relatively easy XNA framework you should at least read all the C++ tutorials as XNA is in C#, still a bit far from C++ but until I make C# tutorials C++ will get you close enough. If you choose to go with the GDI first, either to get a sense of what a pain graphics were before Direct2D and other tools, or just to keep the legacy going, you can proceed with the Win32Api/GDI tutorials, all this was created with C and has no dependency of C++, however I would suggest you practice before going in that direction since you will have some hard time handling some issues.

The choice is yours, but make sure you make a game or two with simple C, the other stuff might be very hard to deal with if you are not familiar with these.