C for Yourself - part 9

In the second part of the tutorial explaining how to use functions in C, David Matthewman explains how to pass arguments to and from a function.

A function that cannot communicate with the rest of the program is of limited use. You might conceivably have a function mode45() which changed screen mode to mode 45, or blob() which generated a dingbats character, but in general you will want to pass information to and from a function.

Last issue we saw one way of getting information from a function, by using the return statement. We also saw how information is passed to the function in function arguments, which are listed with their types in the definition of the function.

How arguments are passed

I will now look in more detail at how arguments are passed to functions. In a program:

int square(int x)
{
  x = x * x;
  return x;
}

int main()
{
  int number;
  
  ...
  
  number = square(number);
}

the function square() takes an integer parameter, x. When it is called from main() the integer variable number is used as an argument.

Incidentally, it is conventional to use parameter when referring to a variable in the list in brackets in a function declaration, and argument for the variable in brackets when the function is called. Functions are passed arguments when they are called; they take parameters. This convention is observed above, and will be from now on.

When number is passed to the function, a copy of it is used, and its value assigned to the parameter x. x is therefore not the same as number, in fact it is a complete different variable which happens to have the same value. An implicit:

x = number;

instruction is issued by the compiler, even to the extent that if number is a different type of variable to x it will be cast to the correct type as it is passed. (The compiler may warn about this, and will generate an error if the cast cannot be done legally.)

Because an argument is copied to the parameter of a function when it is called, changing the value of the parameter will not change the original argument's value. When the value of x is squared within the function the value of number is unaffected. This is why the explicit return statement is needed.

Local variables

Another point to note is that function parameters are local to the function in which they are declared. Therefore x is unaccessible outside the function square() - in fact, it does not necessarily exist. Were we to set up a pointer to x, that pointer would become invalid as soon as the function was returned from. This applies whattever the scope of the pointer; if it is pointing to a variable which is local to a function, its value is invalid outside the function. The memory to which it points may be re-allocated by the C compiler at any time outside the function.

On the whole though, this is a good thing, as it means that the function can do exactly as it pleases with the value of x without having to worry about changing the value of either the original argument or any other variable called x that there may happen to be in the program.

Passing pointers

The fact that arguments are only copied to a function may seem a little limiting. Sometimes we might want the function to change the value of an argument. If there is only one value which needs changing, then it can be passed back in a return statement, as was done with the square() function. However, sometimes it is useful to be able to affect more than one variable.

The classic example of this is the swap() function, to swap the values of two variables. What we would like to be able to do is this:

swap(x, y);

but we can't, because whatever the function does to the values of the arguments passed to it won't affect the arguments in the main program.

However, if we pass pointers to the variables to the functions, then we will be able to change their values. In taking a copy of the pointer, the function now knows the address of the original variable and modify it freely. The use of the * and & operators in C makes this very easy indeed:

void swap(int *first, int *second)
{
  int temp;
  
  temp = *first;
  *first = *second;
  *second = temp;
}

int main()
{
  int x, y;
  
  ...
  
  swap(&x, &y);
}

Here, the parameters of swap() have type 'pointer to int' and indeed when it is called, it is passed pointers to x and y. By using *first and *second as though they were int variables - they are identical to x and y in the main program in all but name - the values of x and y are swapped within the function. These function was never aware of the variables x and y by name, but it knew their addresses and therefore could change their values.

Arrays are never used as arguments to functions in C, but are always passed by using the name of the array, which is of course a pointer to the array's first element. Therefore changing the contents of an array in a function will change the array's contents in the main program; this is demonstrated by Kate4 on the disc. Individual elements of the array can be used as arguments. Actually, arrays can be passed to functions as part of structures, but that is a story for a much later issue.


Source: Acorn User - 153 - March 1995
Publication: Acorn User
Contributor: David Matthewman