Pointers in C: Pointers and Functions

Pointers and functions get along quite well together. That is, you can pass a pointer as an argument to a function in the normal fashion, and you can also have a function return a pointer as its result.

The first case cited previously, passing pointer arguments, is straightforward enough: The pointer is simply included in the list of arguments to the function in the normal fashion. So, to pass the pointer list_pointer from the previous program to a function called print_list, you can write

print_list (list_pointer);

Inside the print_list routine, the formal parameter must be declared to be a pointer to the appropriate type:

void print_list (struct entry *pointer)

{

}

The formal parameter pointer can then be used in the same way as a normal pointer variable. One thing worth remembering when dealing with pointers that are sent to functions as arguments: The value of the pointer is copied into the formal parameter when the function is called. Therefore, any change made to the formal parameter by the function does not affect the pointer that was passed to the function. But here’s the catch: Although the pointer cannot be changed by the function, the data elements that the pointer references  can be changed! Program 11.8 helps clarify this point.

Program 11.8   Using Pointers and Functions

// Program to illustrate using pointers and functions

#include <stdio.h>

void test (int *int_pointer)

{

*int_pointer = 100;

}

int main (void)

{

void test (int *int_pointer);

int i = 50, *p = &i;

printf (“Before the call to test i = %i\n”, i);

test (p);

printf (“After the call to test i = %i\n”, i);

return 0;

}

Program 11.8   Output

Before the call to test i = 50

After the call to test i = 100

The function test is defined to take as its argument a pointer to an integer. Inside the function, a single statement is executed to set the integer pointed to by int_pointer to the value 100.

The main routine defines an integer variable i with an initial value of 50 and a point- er to an integer called p that is set to point to i. The program then displays the value of i and calls the test function, passing the pointer p as the argument. As you can see from the second line of the program’s output, the test function did, in fact, change the value of i to 100.

Now consider Program 11.9.

Program 11.9   Using Pointers to Exchange Values

// More on pointers and functions

#include <stdio.h>

void exchange (int * const pint1, int * const pint2)

{

int temp;

temp = *pint1;

*pint1 = *pint2;

*pint2 = temp;

}

int main (void)

{

void exchange (int * const pint1, int * const pint2);

int  i1 = -5, i2 = 66, *p1 = &i1, *p2 = &i2;

printf (“i1 = %i, i2 = %i\n”, i1, i2);

exchange (p1, p2);

printf (“i1 = %i, i2 = %i\n”, i1, i2);

exchange (&i1, &i2);

printf (“i1 = %i, i2 = %i\n”, i1, i2);

return 0;

}

Program 11.9   Output

i1 = -5, i2 = 66

i1 = 66, i2 = -5

i1 = -5, i2 = 66

The purpose of the exchange function is to interchange the two integer values pointed to by its two arguments. The function header

void exchange (int * const pint1, int * const pint2)

says that the exchange function takes two integer pointers as arguments,  and that the pointers will not be changed by the function (the use of the keyword const).

The local integer variable temp is used to hold one of the integer values while the exchange is made. Its value is set equal to the integer that is pointed to by pint1. The integer pointed to by pint2 is then copied into the integer pointed to by pint1, and the value of temp is then stored in the integer pointed to by pint2, thus making the exchange complete.

The main routine defines integers i1 and i2 with values of –5 and 66, respectively. Two integer pointers, p1 and p2, are then defined and are set to point to i1 and i2, respectively. The program then displays the values of i1 and i2 and calls the exchange function, passing the two pointers, p1 and p2, as arguments. The exchange function exchanges the value contained in the integer pointed to by p1 with the value contained in the integer pointed to by p2. Because p1 points to i1, and p2 to i2, the values of i1 and i2 end up getting exchanged by the function. The output from the second printf call verifies that the exchange worked properly.

The second call to exchange is a bit more interesting. This time, the arguments that are passed to the function are pointers to i1 and i2 that are manufactured right on the spot by applying the address operator to these two variables. Because the expression &i1 produces a pointer to the integer variable i1, this is right in line with the type of argu- ment that your function expects for the first argument (a pointer to an integer). The same applies for the second argument as well. And as can be seen from the program’s output, the exchange function did its job and switched the values of i1 and i2 back to their original values.

You should realize that without the use of pointers, you could not have written your exchange function to exchange the value of two integers because you are limited to returning only a single value from a function and because a function cannot permanent- ly change the value of its arguments. Study Program 11.9 in detail. It illustrates with a small example the key concepts to be understood when dealing with pointers in C.

Program 11.10 shows how a function can return a pointer. The program defines a function called findEntry whose purpose is to search through a linked list to find a specified value. When the specified value is found, the program returns a pointer to the entry in the list. If the desired value is not found, the program returns the null pointer.

Program 11.10   Returning  a Pointer from a Function

#include <stdio.h>

struct entry

{

int value;

struct entry *next;

};

struct entry *findEntry (struct entry *listPtr, int match)

{

while ( listPtr != (struct entry *) 0 )

if ( listPtr->value == match )

return (listPtr);

else

listPtr = listPtr->next;

return (struct entry *) 0;

}

int main (void)

{

struct entry *findEntry (struct entry *listPtr, int match);

struct entry n1, n2, n3;

struct entry *listPtr, *listStart = &n1;

 

int search;

 

n1.value = 100;

n1.next = &n2;

 

n2.value = 200;

n2.next = &n3;

 

n3.value = 300;

n3.next = 0;

 

printf (“Enter value to locate: “);

scanf (“%i”, &search);

listPtr = findEntry (listStart, search);

if ( listPtr != (struct entry *) 0 )

printf (“Found %i.\n”, listPtr->value);

else

printf (“Not found.\n”);

return 0;

}

Program 11.10   Output

Enter value to locate: 200

Found 200.

Program 11.10   Output (Rerun)

Enter value to locate: 400

Not found.

Program 11.10   Output (Second  Rerun)

Enter value to locate: 300

Found 300.

The function header

struct entry *findEntry (struct entry *listPtr, int match)

specifies that the function findEntry returns a pointer to an entry structure and that it takes such a pointer as its first argument and an integer as its second. The function begins by entering a while loop to sequence through the elements of the list. This loop is exe- cuted until either match is found equal to one of the value entries in the list (in which case the value of listPtr is immediately returned) or until the null pointer is reached (in which case the while loop is exited and a null pointer is returned).

After setting up the list as in previous programs, the main routine asks the user for a value to locate in the list and then calls the findEntry function with a pointer to the start of the list (listStart) and the value entered by the user (search) as arguments. The pointer that is returned by findEntry is assigned to the struct entry pointer variable listPtr. If listPtr is not null, the value member pointed to by listPtr is displayed. This should be the same as the value entered by the user. If listPtr is null, then a “Not found.” message is displayed.

The program’s output verifies that the values 200 and 300 were correctly located in the list, and the value 400 was not found because it did not, in fact, exist in the list.

The pointer that is returned by the findEntry function in the program does not seem to serve any useful purpose. However, in more practical situations, this pointer might be used to access other elements contained in the particular entry of the list. For example, you could have a linked list of your dictionary entries from Chapter 10, “Character Strings.” Then, you could call the findEntry function (or rename it lookup as it was called in that chapter) to search the linked list of dictionary entries for the

given word. The pointer returned by the lookup function could then be used to access the definition member of the entry.

Organizing the dictionary as a linked list has several advantages. Inserting a new word into the dictionary is easy: After determining where in the list the new entry is to be inserted, it can be done by simply adjusting some pointers, as illustrated  earlier in this chapter. Removing an entry from the dictionary is also simple. Finally, as you learn in Chapter 17, this approach also provides the framework that enables you to dynamically expand the size of the dictionary.

However, the linked list approach for the organization of the dictionary does suffer from one major drawback:You cannot apply your fast binary search algorithm to such a list. This algorithm only works with an array of elements that can be directly indexed. Unfortunately, there is no faster way to search your linked list other than by a straight, sequential search because each entry in the list can only be accessed from the previous one.

One way to glean the benefits of easy insertion and removal of elements,  as well as fast search time, is by using a different type of data structure known as a tree. Other approaches, such as using hash tables, are also feasible. The reader is respectfully referred elsewhere—such  as to The Art of Computer  Programming,Volume 3, Sorting and Searching (Donald E. Knuth, Addison-Wesley)—for  discussion of these types of data structures, which can be easily implemented in C with the techniques already described.

Source: Kochan Stephen G. (2004), Programming in C: A Complete Introduction to the C Programming Language, Sams; Subsequent edition.

Leave a Reply

Your email address will not be published. Required fields are marked *