1 <!DOCTYPE HTML PUBLIC
"-//W3O//DTD W3 HTML 2.0//EN">
2 <!-- This collection of hypertext pages is Copyright 1995-7 by Steve Summit. -->
3 <!-- This material may be freely redistributed and used -->
4 <!-- but may not be republished or sold without permission. -->
7 <link rev=
"owner" href=
"mailto:scs@eskimo.com">
8 <link rev=
"made" href=
"mailto:scs@eskimo.com">
9 <title>24.2 What are Function Pointers Good For?
</title>
10 <link href=
"sx10a.html" rev=precedes
>
11 <link href=
"sx10c.html" rel=precedes
>
12 <link href=
"sx10.html" rev=subdocument
>
15 <H2>24.2 What are Function Pointers Good For?
</H2>
17 <p>In this section we'll list several situations
18 where function pointers can be useful.
19 </p><p>A common problem is
<dfn>sorting
</dfn>,
21 rearranging a set of items into a desired sequence.
22 It's especially common for the
24 to be contained in an array.
25 Suppose you were writing a function to sort an array of strings.
27 the algorithm for sorting the elements of an array looks like this:
29 for all pairs of elements in the array
30 if the pair is out of order
33 </I></blockquote>In C,
34 the outline of the function might therefore look like this:
36 stringsort(char *strings[], int nstrings)
38 for(
<I>all pairs of elements
</I> i
<I>,
</I> j
<I>in
</I> strings )
40 if(strcmp(strings[i], strings[j])
> 0)
42 char *tmp = strings[i];
43 strings[i] = strings[j];
50 the library function
<TT>strcmp
</TT> compares two strings
51 and returns either a negative number, zero, or a positive number
52 depending on whether the first string was ``less than,''
53 the same as, or ``greater than'' the second string.
54 If you haven't seen it before,
55 the series of three assignments
56 involving the temporary variable
<TT>tmp
</TT>
57 is a standard idiom for swapping two items.
58 (The more obvious pair of assignments
60 strings[i] = strings[j];
61 strings[j] = strings[i];
63 would just about as obviously not work,
64 because the first line would obliterate
<TT>strings[i]
</TT>
65 before the second line had a chance to assign it to
<TT>string[j]
</TT>.)
67 a real sort function implementing a real sorting algorithm
68 will be a bit more elaborate;
69 in particular, the details of how we choose
70 which pairs of elements to compare
72 can make a huge difference in how efficiently
73 the function completes its job.
74 We'll show a complete example in a minute,
76 our more important focus is on the comparison step.
77 The final ordering of the strings
78 will depend on the
<TT>strcmp
</TT> function's definition
79 of what it means for one string to be
80 ``less than'' or ``greater than'' another.
81 How
<TT>strcmp
</TT> compares strings
86 is to look at them a character at a time,
87 based on their values in the machine's character set
88 (which is how C always treats characters).
89 In ASCII, the character set that most computers use,
90 the codes representing the letters are in order,
91 so
<TT>strcmp
</TT> gives you something
92 pretty close to alphabetical order,
93 with the significant difference that all the upper-case letters
94 come before the lower-case letters.
95 So a string-sorting function built around
<TT>strcmp
</TT>
109 </blockquote><TT>strcmp
</TT> is quite useless for sorting strings
110 which consist entirely of digits,
111 because it goes from left to right,
112 stopping when it finds the first difference,
113 without regard to whether it was comparing
114 the ten's digit of one number to the hundred's of another.
115 For example, a
<TT>strcmp
</TT>-based sort
116 would sort the strings
135 </p><p>Depending on circumstances,
136 we might want our string sorting function to sort
137 into the order that
<TT>strcmp
</TT> uses,
138 or into ``dictionary''
141 (that is, with all the a's together, both upper-case and lower-case),
142 or into numeric order.
143 We could pass our
<TT>stringsort
</TT> function a flag or code
144 telling it which comparison strategy to use,
145 although that would mean that whenever we invented
146 a new comparison strategy,
147 we would have to define a new code or flag value
148 and rewrite
<TT>stringsort
</TT>.
149 But, if we observe that the final ordering
150 depends entirely on the behavior of the comparison function,
151 a neater implementation is if we write our
<TT>stringsort
</TT> function
152 to accept a pointer to the function which we want it to use
153 to compare each pair of strings.
154 It will go through its usual routine of comparing and exchanging,
155 but whenever it makes the comparisons,
156 the actual function it calls will be
157 the function pointed to by the function pointer we hand it.
158 Making it sort in a different order,
159 according to a different comparison strategy,
160 will then not require rewriting
<TT>stringsort
</TT> at all,
163 passing it a pointer to a different comparison function
164 (after perhaps writing that function).
165 </p><p>Here is a complete implementation of
<TT>stringsort
</TT>,
166 which also accepts a pointer to the string comparison function:
168 void stringsort(char *strings[], int nstrings, int (*cmpfunc)())
175 for(i =
0; i
< nstrings -
1; i++)
178 if((*cmpfunc)(strings[i], strings[j])
> 0)
180 char *tmp = strings[i];
181 strings[i] = strings[j];
189 (This code uses a fairly simpleminded sorting algorithm.
190 It repeatedly compares adjacent pairs of elements,
191 keeping track of whether it had to exchange any.
192 If it makes it all the way through the array
193 without exchanging any, it's done;
194 otherwise, it has at least made progress,
195 and it goes back for another pass.
196 This is not the world's best algorithm;
197 in fact it's not far from
198 the infamous ``bubble sort.''
199 Although our focus here is on function pointers,
201 in a minute we'll take time out
202 and look at a simple improvement to this algorithm
203 which
<em>does
</em> make it a decent one.)
204 </p><p>Now, if we have an array of strings
206 char *array1[] = {
"Zeppelin",
"able",
"baker",
"Charlie"};
208 we can sort it into
<TT>strcmp
</TT> order by calling
210 stringsort(array1,
4, strcmp);
214 in this call, we are
<em>not
</em> calling
<TT>strcmp
</TT> immediately;
215 we are generating a pointer to
<TT>strcmp
</TT>,
216 and passing that pointer as the third argument
217 in our call to
<TT>stringsort
</TT>.
218 </p><p>If we wanted to sort these words in ``dictionary'' order,
220 we could write a version of
<TT>strcmp
</TT> which ignores case
221 when comparing letters:
223 #include
<ctype.h
>
225 int dictstrcmp(char *str1, char *str2)
245 (The functions
<TT>isupper
</TT> and
<TT>tolower
</TT>
246 are both from the standard library
247 and are declared in
<TT><ctype.h
></TT>.
248 <TT>isupper
</TT> returns ``true''
249 if its argument is an upper-case letter,
250 and
<TT>tolower
</TT> converts its argument to a lower-case letter.)
251 </p><p>With
<TT>dictstrcmp
</TT> in hand,
252 we can sort our array a different way:
254 stringsort(array1,
4, dictstrcmp);
256 (Some C libraries contain case-independent versions of
<TT>strcmp
</TT>
257 called
<TT>stricmp
</TT> or
<TT>strcasecmp
</TT>.
259 Both of these would do the same thing as our
<TT>dictstrcmp
</TT>,
260 although neither of them is standard.)
261 </p><p>We can also write another string-comparison function
262 which treats the strings as numbers,
263 and compares them numerically:
265 int numstrcmp(char *str1, char *str2)
269 if(n1
< n2) return -
1;
270 else if(n1 == n2) return
0;
274 </p><p>Then, we can sort an array of numeric strings correctly:
276 char *array2[] = {
"1",
"234",
"12",
"3",
"4",
"24",
"2"};
277 stringsort(array2,
7, numstrcmp);
280 you will occasionaly see code
281 which is supposed to compare two integers
282 and return a negative, zero, or positive result--i.e. just
283 like the
<TT>numstrcmp
</TT> function above--but
284 which does so by the seemingly simpler technique of just saying
288 It turns out that this trick has a serious drawback.
289 Suppose that
<TT>n1
</TT> is
32000, and
<TT>n2
</TT> is -
32000.
290 Then
<TT>n1 - n2
</TT> is
64000,
291 which is not guaranteed to fit in an
<TT>int
</TT>,
292 and will overflow on some machines,
293 producing an incorrect result.
294 So the explicit comparison code
295 such as
<TT>numcmp
</TT> used
296 is considerably safer.)
297 </p><p>Finally, since we've started looking at sorting functions,
298 let's look at a simple improvement to the string sorting function
299 we've just been using.
300 It has been plodding along comparing
303 when an element is far out of place,
304 it takes many passes to percolate it to the correct position
305 (one cell at a time).
309 based on the work of Donald L. Shell,
310 is to compare pairs of more widely-separated elements at first,
311 then proceed to compare more and more closely-situated elements,
312 until on the last pass
314 we compare adjacent elements, as before.
315 Since the earlier passes will have done more of the work
317 the later passes will just have to do the ``final cleanup.''
318 Here is the improvement:
320 void stringsort(char *strings[], int nstrings, int (*cmpfunc)())
325 for(gap = nstrings /
2; gap
> 0; gap /=
2)
329 for(i =
0; i
< nstrings - gap; i++)
332 if((*cmpfunc)(strings[i], strings[j])
> 0)
334 char *tmp = strings[i];
335 strings[i] = strings[j];
344 The inner loops are the same as before,
345 except that where we had before always been computing
348 <TT>j = i + gap
</TT>,
349 where
<TT>gap
</TT> is a new variable
350 (controlled by a third, outer loop)
351 which starts out large
352 (
<TT>nstrings /
2</TT>),
353 and then diminishes until it's
1.
354 Although this code contains three nested loops instead of two,
355 it will end up making far fewer trips through the inner loop,
356 and so will execute faster.
357 </p><p>The Standard C library contains a general-purpose sort function,
358 <TT>qsort
</TT> (declared in
<TT><stdlib.h
></TT>),
359 which can sort any type of data (not just strings).
360 It's a bit trickier to use (due to this generality),
361 and you almost always have to write an auxiliary comparison function.
363 due to the generic way in which
<TT>qsort
</TT> calls your comparison function,
364 you can't use
<TT>strcmp
</TT> directly
365 even when you're sorting strings
366 and would be satisfied with
<TT>strcmp
</TT>'s ordering.
367 Here is an auxiliary comparison function
368 and the corresponding call to
<TT>qsort
</TT>
369 which would behave like our earlier call to
370 <TT>stringsort(array1,
4, strcmp)
374 /* compare strings via pointers */
375 int pstrcmp(const void *p1, const void *p2)
377 return strcmp(*(char * const *)p1, *(char * const *)p2);
382 qsort(array1,
4, sizeof(char *), pstrcmp);
384 When you call
<TT>qsort
</TT>,
385 it calls your comparison function
386 with pointers to the elements of your array.
387 Since
<TT>array1
</TT> is an array of pointers,
388 the comparison function ends up receiving pointers to pointers.
389 But
<TT>qsort
</TT> doesn't know that the array is an array of pointers;
390 it's written so that it can sort arrays of anything.
391 (That's why
<TT>qsort
</TT>'s third argument
393 is the size of the array element.)
394 Since
<TT>qsort
</TT> doesn't know
395 what the type of the elements being sorted is,
396 it uses
<TT>void
</TT> pointers
398 when it calls the comparison function.
399 (The use of
<TT>void
</TT> pointers here recalls their use with
<TT>malloc
</TT>,
400 where the situation is similar:
401 <TT>malloc
</TT> returns pointers to
<TT>void
</TT>
402 because it doesn't know what type we'll use the pointers to point to.)
403 In the ``wrapper'' function
<TT>pstrcmp
</TT>,
407 </TT>to convert the
<TT>void
</TT> pointers which the function receives
408 into pointers to (pointers to
<TT>char
</TT>)
409 so that when we use one
<TT>*
</TT> operator
410 to find out what they point to,
411 we get one of the character pointers (
<TT>char *
</TT>)
412 which we know our
<TT>array1
</TT> array actually contains.
413 We pass the resulting two
<TT>char *
</TT>'s to
<TT>strcmp
</TT>
414 to do most of the work,
415 but we have to do a bit of work first to recover the correct pointers.
416 (The extra
<TT>const
</TT>
419 </TT>keeps the compiler from complaining,
420 since the pointers being passed in to the comparison function
421 are actually
<TT>const void *
</TT>,
422 meaning that although it may not be clear what they point to,
424 we won't be using them
425 to modify whatever it is they point to.
426 We need to keep a level of
<TT>const
</TT>-ness in the converted pointers
427 so that the compiler doesn't worry
428 that we're going to accidentally use the converted pointers
429 to modify what we shouldn't.)
432 </p><p>That was a rather elaborate first example
433 of what function pointers can be used for!
434 Let's move on to some others.
435 </p><p>Suppose you wanted a program to plot equations.
436 You would give it a range of
<I>x
</I> and
<I>y
</I> values
437 (perhaps -
10 to
10 along each axis),
438 and ask it to plot
<I>y = f(x)
</I> over that range
439 (e.g. for -
10 <=
<I>x
</I> <=
10).
440 How would you tell it what function to plot?
441 By a function pointer, of course!
442 The plot function could then step its
<TT>x
</TT> variable
443 over the range you specified,
444 calling the function pointed to by your pointer
445 each time it needed to compute
<TT>y
</TT>.
448 plot(-
10,
10, -
10,
10, sin)
453 plot(-
10,
10, -
10,
10, sqrt)
455 to plot the square root function.
456 </p><p>(If you were to try to write this
<TT>plot
</TT> function,
457 your first question would be
458 how to draw lines or otherwise do graphics in C at all,
459 and unfortunately this is one of the questions
460 which the C language doesn't answer.
461 There are potentially different ways of doing graphics,
462 with different system functions to call,
463 for every different kind of computer,
465 and graphics device.)
466 </p><p>One of the simplest
467 (and allegedly least user-friendly)
468 styles of user interfaces
469 is the
<dfn>command line interface
</dfn>,
471 The user types a command, hits the RETURN key,
472 and the system interprets the command.
473 Often, the first ``word'' on the line is the command name,
474 and any remaining words are
475 ``arguments'' or ``option flags.''
476 The various shells under Unix,
477 COMMAND.COM under MS-DOS,
478 and the adventure game we've been writing
479 are all examples of CLI's.
480 If you sit down to write some code implementing a CLI,
481 it's simple enough to read a line of text typed by the user,
482 and simple enough to break it up into words.
483 But how do you map the first word on the line
484 to the code which implements that command?
485 A straightforward, rather simpleminded way
486 is to use a giant
<TT>if
</TT>/
<TT>else
</TT> chain:
488 if(strcmp(command,
"agitate") ==
0)
489 {
<I>code for ``agitate'' command
</I> }
490 else if(strcmp(command,
"blend") ==
0)
491 {
<I>code for ``blend'' command
</I> }
492 else if(strcmp(command,
"churn") ==
0)
493 {
<I>code for ``churn'' command
</I> }
495 else fprintf(stderr,
"command not found\n");
497 </p><p>This works, but can become unwieldy.
498 Another technique is to write several separate functions,
499 each implementing one command,
500 and then to build a table
501 (typically an array of structures)
502 associating the command name as typed by the user
503 with the function implementing that command.
505 the command name is a string
506 and the function is represented by a function pointer.
507 With this table in hand,
508 processing the user's command becomes a relatively simple matter
509 of searching the table for the matching command string
510 and then calling the corresponding pointed-to function.
512 (We'll see an example
514 in this week's assignment.)
515 </p><p>Our last example concerns larger, more elaborate systems
516 which manipulate many types of data.
517 (Here, by ``types of data,''
518 I am referring to data structures used by the program,
519 presumably implemented as
<TT>struct
</TT>s,
521 more elaborate than C's basic data types.)
522 It is often the case that similar operations
523 must be performed on dissimilar data types.
524 The conventional way of implementing such operations
525 is to have the code for each operation
526 look at the data type it's operating on
527 and adjust its behavior accordingly;
531 will have a long
<TT>switch
</TT> statement
532 or
<TT>if
</TT>/
<TT>else
</TT> chain
533 switching among
<I>n
</I> separate, different ways
534 of performing the operation on
<I>n
</I> different data types.
535 If a new data type is ever added,
536 new cases must be added to all
539 implementing all of the operations.
540 </p><p>Another way of organizing such code
541 is to place one or more function pointers
544 in the data structures describing each data type.
545 These pointers point to functions
546 which are streamlined and optimized
547 for performing the operations on just one data type.
548 (Each piece of data would obviously have its pointer(s) set
549 to point to the function(s) for its own data type.)
550 This idea is one of the cornerstones of
551 <dfn>Object-Oriented Programming
</dfn>.
552 We could use a version of it in our adventure game, too:
553 rather than writing new, global pieces of code
554 implementing each new command verb we want to let the user type,
555 and then making each of those pieces of code
556 check all sorts of attributes
557 to ensure that the command can't be used on inappropriate objects
558 (``break water with cup'',
559 ``light candle with bucket,'' etc.)
560 we could attach special-purpose pieces of code
561 to the individual objects themselves
562 (via function pointers, of course)
563 and arrange that the code would only fire up
564 if the player were trying to use the relevant object.
568 <a href=
"sx10a.html" rev=precedes
>prev
</a>
569 <a href=
"sx10c.html" rel=precedes
>next
</a>
570 <a href=
"sx10.html" rev=subdocument
>up
</a>
571 <a href=
"top.html">top
</a>
574 This page by
<a href=
"http://www.eskimo.com/~scs/">Steve Summit
</a>
575 //
<a href=
"copyright.html">Copyright
</a> 1996-
1999
576 //
<a href=
"mailto:scs@eskimo.com">mail feedback
</a>