|Fundamental C - Functions|
|Written by Harry Fairhead|
|Monday, 19 March 2018|
Page 2 of 2
What if a function doesn't return a value?
This is allowed. Sometimes a function just does something and doesn't need to return a value. For example. the hello program, our first example of a function simply prints a value and returns with out a return value. You can include a return statement anywhere within a function to bring it to an end with or without a return value.
It is good practice to always include a return statement within a function.
One final complication. How do you indicate the type of a function that doesn't return a value?
The answer is to use the type void. This makes C programs look mysterious but all it means is something like "nothing" or "not applicable" or ...
So the hello program really should be written:
You will discover that C tends to use the term "void" when anything isn't of a fixed or known type.
The main Function
If you look again at any C program you will now recognize the main program as actually being the main function. The main function is just a standard function that is automatically called when your program is loaded. It then proceeds to get the work done by calling other functions.
The only thing that might puzzle you at this stage are the strange looking parameters. To understand these in detail we will have to find out about pointers in a later chapter.
So far we have followed the rule that a function is declared before we attempt to use it. This results in all the functions used in a program being listed first and then the code that uses them. To many programmers this is the wrong way round. They want to read the main program first and find out what it does and then read the functions that it uses and then the functions that they use and so on.
You can place a functions code anywhere within the file, or even in another file as long as you include a short declaration - a prototype - for the function before it is used. A prototype simply specifies what the types are that are used in the function declaration.
For example the add function's prototype is:
which declares a that the add function takes two int parameters and returns an int. You can include parameter names if you want to but it general practice to strip the prototype down to just the types.
As long as the prototype is included in the file before the first use of the function everything will work. The full declaration of the function can be later in the file or in another file altogether. The prototype provides enough information for the compiler to check that you are using the function correctly.
The Expression Principle - Pass-by-Value
There is a general principle in C that anywhere you can use a number you can use an expression that evaluates to the same type of value.
Until now we have been setting parameters to values but in fact you can pass a function an expression and this will be evaluated before the function is executed.
in this case the multiplication is performed and 6 is passed to the function.
Of course an expression can involve variables.
in this case the value in count is multiplied by 3 and the result passed to the function.
The limiting case of an expression is just a variable:
In this case the value in count is passed into the function.
This is usually called pass-by-value and it is one of the possible ways of passing data into functions. It is one of the simplest and you should now be able to understand what happens in the following example:
The question is what does a store after the function call? Is it 1 which is what it was assigned in the function or is it its original value of 0?
The answer is that it still holds 0. There is no connection between variables outside of the function and the parameters inside the function even if they have the same names. Because of the use of pass-by-value what happens is that the the value of a is passed to the function's parameter which also happens to be called a. When you assign to a in the function it is to a completely different variable than the a outside of the function.
This gives rise to the rule that
modifying variables inside a function has no effect on variables outside of the function.
This is good because it makes function isolated little chunks of code that are easy to understand and check.
There are parameter passing methods that do allow functions to change things outside of their own code and these are more dangerous even if they are sometimes useful. C only uses pass-by-value and we will have to see how to achieve other ways of passing parameters later.
This idea of functions as being isolated chunks of code goes beyond just the parameters. You can declare variables within a function and these are generally called local variables.
For example, in the add function we declared a local variable c:
Just like the parameters this c has nothing to do with any variables called c outside of the function. The local variable c is created when the function starts executing and it is destroyed when the function returns. That is local variables only exist while the function is running - they have the same lifetime as the function.
This should seem very reasonable to you but if you forget it you will try to write something like:
and in the main program:
The idea here is that c is incremented by 1 each time the function is executed but of course this doesn't work. The variable c is destroyed each time the function returns and so it doesn't matter how many times you call counter() c is created anew and set to 0 and then has one added to it. The function always returns 1.
If there are local variables are there global variables?
The answer is yes. In C global variables are often called "file level" variables because they are declared outside of any function.
A global variable will automatically be zeroed to a value that is appropriate for its type but it is usually better to initialize it. The most important thing about global variable is that they are created when the program starts and remain in existence until the program ends. They can also be accessed from within any function. The only exception to this is if the function declares a variable of the same name when the local variable is used - it overrides the global variable.
As a global variable exists for the lifetime of the program you can use to keep track of things throughout the execution of the program so now the counter function can be made to work:
now if you put
in the main program you will see 1 followed by 2 and the variable c is being used to count the number of times the function has been used.
When you first start to construct larger programs there is a tendency to create lots of global variables because this means you don't have to pass them as parameters to functions. The functions can just make use of global variables as if they were their own. The problem is that global variables are not the property of any function and they have to be hard coded into the functions. Using lots of global variables produces a program that is fragile in the sense that any small change can have effects further away from where the change occurred.
Using functions and local variables makes program up out of small isolated units that can be understood and debugged in isolation.
Fundamental C For The IoT & Embedded Programming
Available as a print book very soon - only two chapters left to write! I expect it to be published at the end of 2018.
Part I - The Core Language
or email your comment to: firstname.lastname@example.org
|Last Updated ( Tuesday, 11 September 2018 )|