Functions and Pointers in C: A Brief Guide

Author’s Note: Yet another piece of filler. Basically, I’ve been doing a lot of programming recently, and I wrote this guide as an aid for some people. It’s not particularly long, nor does it contain much insight, but it represents the most substantial piece of writing I could conjure forth this week.

Any arbitrary C program that you see will contain at least one function – main() – and unless it is very simple, more than one. Functions are a way in C to segment a program into several discrete pieces. In almost all cases, a C program could be written entirely in main() with the only calls to external functions being ones in the C standard library, but the program would be a complicated mess, difficult to read and even more difficult to modify or to reuse any of the components.

A C function is declared in two parts: The function declaration, or a statement of intent as to the components of the function; and the function definition, which contains the body of the function. The declaration takes the form of a function prototype, which is usually declared either before or inside the main() function.

A function declaration looks something like this:

int square(int i);

Note the semicolon at the end; the declaration looks similar to declaring a variable. This defines a function named square() with an integer argument and an integer return value. Any use of square() which does not agree with this function declaration is an error.

Once we have the function declaration, we can write the function definition. This looks something like this:

int square(int n)
{
    return n * n;
}

At this point, we can further discuss the arguments and return type of this function. The argument variable, n, is internal to this function, cannot be called by any other function and is separate from any other variables which may happen to be called “n” in other functions. If this argument was called with the value of a variable in another function, the argument is /not/ the same as that variable; it is another variable entirely which just happens to have the value of the initialising variable.

This can be demonstrated with the following simple program:

#include <stdio.h>

int main(void)
{
    int a = 12;
    printf("%d\n", a);
    printf("%d\n", square(a));
    printf("%d\n", a);
    return 0;
}

int square(int i)
{
    i = 5;
    return i * i;
}

 

 

This program has the result:

12

25

12

Even though square() was called with a variable, the function has no access to this variable during its operation. The value of the variable, a, is taken and put into the variable, i, while the program is executing the square function. Changes to i do not affect the corresponding variable in main().

If one actually wants to change the variable, a, in main() with reference to the square function, there are two ways to achieve this. The first is to redefine the variable, a, with the return value of square() in main(), as such:

int main(void)
{
    ...
    a = square(a);
    ...
}

The second is to use a pointer. Before I address this, the question must be asked: Why use pointers in the first place for anything? Firstly, their judicious use can make a program more compact and quicker at the machine-code level, particularly with array referencing. Secondly, they are necessary for dynamic memory allocation (i.e. malloc() and its brethren). Thirdly, they are necessary to provide the address for call-by-reference function declaration. With that in mind, we’ll continue to their use in functions.

Using a pointer in the above program would necessitate a few changes to the already existing function declaration, definition and statement of use in main().

#include <stdio.h>

int square(int *i); /* Notice the use of the asterisk beside i */

int main(void)
{
    int a = 12;
    printf("%d\n", a);
    /* & is the reference operator, and sends the address of a to
     * square rather than the value.
     */
    printf("%d\n", square(&a));
    printf("%d\n", a);
    return 0;
}

int square(int *i)
{
    /* The asterisk is the dereference operator, changing the value
     * stored in the address referred to by the pointer *i.
     */
    *i = 5;
    return (*i) * (*i);
}

Using this notation, the result is:

12

25

5

The reason for this is that unlike the variable i, which stored a value which was equal to that value going into the function, the pointer i, which is dereferenced in the function using *i, stores the address of an already existing variable. The variable i was a separate address from the variable a in main(); the pointer i is a separate address from the variable a, but by containing its address, it can be used to perform operations on that variable from another function.

Another use of pointers is in reference to arrays. Indeed, arrays and pointers are very closely linked, and an array could be thought of as a set of pointers which are contiguous in memory. These two statements are therefore equivalent:

array[1]

*(array+1)

The use of the pointer notation is typically quicker than that of the array notation, but often more difficult to understand. The reason for the additional speed comes from various operations at the machine-code level; usually, however, the use of array notation won’t result in any adverse effects to the speed of the program.

One of the other uses of pointers is in dynamic memory allocation using the likes of malloc(). A call to malloc() looks something like this:

/* Use malloc to create an array of 1000 int variables */

int *array = (int *) malloc (1000 * sizeof(int))

 

 

The syntax of malloc() looks unfriendly, particularly due to the cast to a typed pointer that needs to be put before it. This is because malloc() returns something called a pointer to void (i.e. void *), which is like a generic pointer which can be cast to any typed pointer, and to which all typed pointers can be casted to. Using this intermediate, generic pointer is the only way to change the type of pointers. Any other typecasting operation on pointers is illegal and will show up as an error in the compiler.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: