Previous Page
Next Page

7.4. Pointers as Arguments and Return Values

C is inherently a call by value language, as the parameters of a function are local variables initialized with the argument values. This type of language has the advantage that any expression desired can be used as an argument, as long as it has the appropriate type. On the other hand, the drawback is that copying large data objects to begin a function call can be expensive. Moreover, a function has no way to modify the originalsthat is, the caller's variablesas it knows how to access only the local copy.

However, a function can directly access any variable visible to the caller if one of its arguments is that variable's address. In this way C also provides call by reference functions. A simple example is the standard function scanf( ), which reads the standard input stream and places the results in variables referenced by pointer arguments that the caller provides:

int var;
scanf( "%d", &var );

This function call reads a string as a decimal numeral, converts it to an integer, and stores the value in the location of var.

In the following example, the initNode( ) function initializes a structure variable. The caller passes the structure's address as an argument.

#include <string.h>                 // Prototypes of memset( ) and strcpy( ).
struct Node { long key;
              char name[32];
              /* ... more structure members ... */
              struct Node *next;
            };

void initNode( struct Node *pNode )      // Initialize the structure *pNode.
{
  memset( pNode, 0, sizeof(*pNode) );
  strcpy( pNode->name, "XXXXX" );
}

Even if a function needs only to read and not to modify a variable, it still may be more efficient to pass the variable's address rather than its value. That's because passing by address avoids the need to copy the data; only the variable's address is pushed onto the stack. If the function does not modify such a variable, then you should declare the corresponding parameter as a "read-only" pointer, as in the following example:

void printNode( const struct Node *pNode );
{
  printf( "Key:  %ld\n", pNode->key );
  printf( "Name: %s\n",  pNode->name );
  /* ... */
}

You are also performing a "call by reference" whenever you call a function using an array name as an argument, because the array name is automatically converted into a pointer to the array's first element. The addArray( ) function defined in Example 7-4 has two such pointer parameters.

Often functions need to return a pointer type as well, as the mkNode( ) function does in the following example. This function dynamically creates a new Node object and gives its address to the caller:

#include <stdlib.h>
struct Node *mkNode( )
{
  struct Node *pNode = malloc( sizeof(struct Node) );
  if ( pNode != NULL )
    initNode( pNode );
  return pNode;
}

The mkNode( ) function returns a null pointer if it fails to allocate storage for a new Node object. Functions that return a pointer usually use a null pointer to indicate a failure condition. For example, a search function may return the address of the desired object, or a null pointer if no such object is available.


Previous Page
Next Page